2014-10-30NOIP复习题1

Posted white_hat_hacker

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2014-10-30NOIP复习题1相关的知识,希望对你有一定的参考价值。

Problem 1 Graph (graph.cpp/c/pas)

 

【题目描述】

给出 N 个点,M 条边的有向图,对于每个点 v,求 A(v) 表示从点 v 出发,能到达的编号最大的点。

 

【输入格式】

 1 行,2 个整数 N,M 接下来 M 行,每行 2 个整数 Ui,Vi,表示边 ?Ui,Vi?。点用 1,2,...,N 编号。

 

【输出格式】

N 个整数 A(1),A(2),...,A(N)。

 

【样例输入】

4 3

1 2

2 4

4 3

【样例输出】

4 4 3 4

【数据范围】

对于 60% 的数据,1 ≤ N,K ≤ 10^3

对于 100% 的数据,1 ≤ N,M ≤ 10^5。

Problem 2 Incr(incr.cpp/c/pas)

 

【题目描述】

数列 A1,A2,...,AN,修改最少的数字,使得数列严格单调递增。

 

【输入格式】

1 行,1 个整数 N

2 行,N 个整数 A1,A2,...,AN

【输出格式】

1 个整数,表示最少修改的数字

 

【样例输入】

3

1 3 2

【样例输出】

1

【数据范围】

对于 50% 的数据,N ≤ 10^3

对于 100% 的数据,1 ≤ N ≤ 10^5,1 ≤ Ai ≤ 10^9

Problem 3 Permutation (permutation.cpp/c/pas)

 

【题目描述】

1 到 N 任意排列,然后在排列的每两个数之间根据他们的大小关系插入“>”和“<”。

问在所有排列中,有多少个排列恰好有K个“<”。

例如排列(3, 4, 1, 5, 2)

3 < 4 > 1 < 5 > 2

共有2个“<”

 

【输入格式】

N,K

 

【输出格式】

答案

 

【样例输入】

5 2

【样例输出】

66

【数据范围】

20%:N <= 10

50%:答案在0..2^63-1内

100%:K < N <= 100


NOIP复习题旨在复习知识点,故写详细一点啦

T1:

强联通分量缩点的裸题(我当时竟然以为第一题应该不会太难而没考虑环,结果40分炸掉QAQ)

我用的是Kosaraj+dfs缩点,效率很低

不过还是写一下吧,反正我不会tarjan~

先是两遍深搜获取基本信息,然后再一遍深搜把各个缩点连接起来

最后一遍拓扑排序。

总共四边搜索,四次清空bool数组,三个邻接表

程序太垃圾啦~

技术分享
  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<vector>
  6 #define MAXN 100005
  7 using namespace std;
  8 vector<int> G[MAXN];
  9 vector<int> rG[MAXN];
 10 vector<int> nG[MAXN];
 11 vector<int> vs;
 12 int cmp[MAXN],cnt;
 13 int m[MAXN];
 14 int b[MAXN];
 15 int ru[MAXN];
 16 int V,E;
 17 void dfs1(int x){
 18     b[x]=1;
 19     for(int i=0;i<G[x].size();i++){
 20         int y=G[x][i];
 21         if(!b[y]){
 22             dfs1(y);
 23         }
 24     }
 25     vs.push_back(x);
 26 }
 27 void dfs2(int x){
 28     b[x]=1;
 29     cmp[x]=cnt;
 30     m[cnt]=max(m[cnt],x);
 31     for(int i=0;i<rG[x].size();i++){
 32         int y=rG[x][i];
 33         if(!b[y]){
 34             dfs2(y);
 35         }
 36     }
 37 }
 38 void suo(int x){
 39     b[x]=1;
 40     for(int i=0;i<G[x].size();i++){
 41         int y=G[x][i];
 42         if(cmp[x]!=cmp[y]){
 43             nG[cmp[x]].push_back(cmp[y]);
 44             ru[cmp[y]]++;
 45         }
 46         if(!b[y]){
 47             suo(y);
 48         }
 49     }
 50 }
 51 void topoSort(int x){
 52     b[x]=1;
 53     for(int i=0;i<nG[x].size();i++){
 54         int y=nG[x][i];
 55         if(!b[y]){
 56             topoSort(y);
 57         }
 58         m[x]=max(m[x],m[y]);
 59     }
 60 }
 61 int main()
 62 {
 63 //    freopen("data.in","r",stdin);
 64     scanf("%d%d",&V,&E);
 65     for(int i=1;i<=E;i++){
 66         int x,y;
 67         scanf("%d%d",&x,&y);
 68         G[x].push_back(y);
 69         rG[y].push_back(x);
 70     }
 71     memset(b,0,sizeof(b));
 72     for(int i=1;i<=V;i++){
 73         if(!b[i]){
 74             dfs1(i);
 75         }
 76     }
 77     memset(b,0,sizeof(b));
 78     for(int i=vs.size()-1;i>=0;i--){
 79         cnt++;
 80         int x=vs[i];
 81         if(!b[x]){
 82             dfs2(x);
 83         }
 84     }
 85     memset(b,0,sizeof(b));
 86     for(int i=1;i<=V;i++){
 87         if(!b[i]){
 88             suo(i);
 89         }
 90     }
 91     memset(b,0,sizeof(b));
 92     for(int i=1;i<=cnt;i++){
 93         if(!ru[i]){
 94             topoSort(i);
 95         }
 96     }
 97     for(int i=1;i<=V;i++){
 98         printf("%d ",m[cmp[i]]);
 99     }
100     return 0;
101 }
Code1

T2:

其实就是n-最大上升序列长度即可

证明如下:

设m=n-最长上升序列长度

1)改变m次一定足以使数列递增

2)改变不到m次一定不足以使数列递增

依次证明:

1)显然成立。。。

2)不到m次,那么就设为x吧(x<m)

那么假设x次操作改变的数列项为b1,b2,……,bx

无视这x项,剩余的项数一定是递增的,即此时上升序列长度为n-x

出现了矛盾:最长上升序列=n-m<n-x

于是得证

然后问题是最长上升序列我竟然有点忘记了

巩固一下:

建立单调栈,使得a[i]<a[i+1]

对于新插入的元素a[i],查找大于等于(注意这里是大于等于,因为是严格递增的,所以不能出现相同)第一个a[Pos]

f[i]=f[Pos-1]+1,然后直接用a[i]更新a[Pos],原因a[i]和a[Pos]的f相同的,但a[i]<=a[Pos],所以状态会更优

技术分享
 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<algorithm>
 4 #include<cstring>
 5 #define MAXN 100005
 6 #define pii pair<int,int>
 7 using namespace std;
 8 pii s[MAXN];
 9 int top=0;
10 int a[MAXN];
11 int f[MAXN];
12 int n;
13 int max_array(){
14     int ret=0;
15     for(int i=1;i<=n;i++){
16         pii t=make_pair(a[i],0);
17         // lower_bound the key should be the same
18         int Pos=lower_bound(s+1,s+top+1,t)-s;
19         f[i]=s[Pos-1].second+1;
20         ret=max(f[i],ret);
21         if(Pos>top){
22             top++;
23         }
24         s[Pos]=make_pair(a[i],f[i]);
25     }
26     return ret;
27 }
28 int main()
29 {
30     scanf("%d",&n);
31     for(int i=1;i<=n;i++){
32         scanf("%d",&a[i]);
33     }
34     int len=n-max_array();
35     printf("%d\n",len);
36     return 0;
37 }
Code2

T3:

这题我做过啊

f[i][j]=f[i-1][j-1]*(i-j)+f[i-1][j]*(j+1)

边界f[1~n][0]=1

关键就是复习一下高精度了

技术分享
 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<algorithm>
 4 #include<cstring>
 5 #define MAXN 105
 6 #define SIZE 1000
 7 using namespace std;
 8 struct BigInt{
 9     int len;
10     int s[SIZE];
11     BigInt(){
12         len=0;
13         memset(s,0,sizeof(s));
14     }
15     BigInt operator = (const BigInt &A){
16         len=A.len;
17         for(int i=1;i<=len;i++){
18             s[i]=A.s[i];
19         }
20         return *this;
21     }
22     friend BigInt operator * (const BigInt &A,const int B){
23         BigInt t;
24         t=A;
25         int L=t.len;
26         for(int i=1;i<=L;i++){
27             t.s[i]*=B;
28         }
29         for(int i=1;i<=L;i++){
30             t.s[i+1]+=(t.s[i]/10);
31             t.s[i]%=10;
32         }
33         while(t.s[L+1]){
34             L++;
35             t.s[L+1]+=(t.s[L]/10);
36             t.s[L]%=10;
37         }
38         t.len=L;
39         return t;
40     }
41     friend BigInt operator + (const BigInt &A,const BigInt &B){
42         BigInt t;
43         t.len=max(A.len,B.len);
44         int L=t.len;
45         for(int i=1;i<=L;i++){
46             t.s[i]=A.s[i]+B.s[i];
47         }
48         for(int i=1;i<=L;i++){
49             t.s[i+1]+=(t.s[i]/10);
50             t.s[i]%=10;
51         }
52         if(t.s[L+1]){
53             L++;
54         }
55         t.len=L;
56         return t;
57     }
58     void Print(){
59         for(int i=len;i>=1;i--){
60             printf("%d",s[i]);
61         }
62         printf("\n");
63     }
64     
65 }f[MAXN][MAXN];
66 int n,k;
67 int main()
68 {
69     scanf("%d%d",&n,&k);
70     for(int i=1;i<=n;i++){
71         f[i][0].len=1,f[i][0].s[1]=1;
72     }
73     for(int i=2;i<=n;i++){
74         for(int j=1;j<n;j++){
75             f[i][j]=f[i-1][j-1]*(i-j)+f[i-1][j]*(j+1);
76         }
77     }
78     f[n][k].Print();
79     return 0;
80 }
Code3

总结:基础知识很重要啊,要不然真是有苦说不出。。。

以上是关于2014-10-30NOIP复习题1的主要内容,如果未能解决你的问题,请参考以下文章

noip复习之数学——数论

关于noip提高组复习

NOIP算法总结与复习

[Noip复习知识点][个人向]Zackzh

NOIP 考前DP 复习

noip复习——线性筛(欧拉筛)