1. 程式人生 > >2014-10-30NOIP復習題1

2014-10-30NOIP復習題1

tarjan oid incr 排序 int() 高精 有向圖 詳細 one

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