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