首页 > 代码库 > Codeforces Round #243
Codeforces Round #243
CF 243 DIV1 & DIV2
DIV2的A和B都太水,直接暴力搞就可以的。
DIV2A
1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2014/4/30 19:42:51 4 File Name :E:\2014ACM\Codeforces\CF243\DIV2_A.cpp 5 ************************************************ */ 6 7 #include <stdio.h> 8 #include <string.h> 9 #include <iostream> 10 #include <algorithm> 11 #include <vector> 12 #include <queue> 13 #include <set> 14 #include <map> 15 #include <string> 16 #include <math.h> 17 #include <stdlib.h> 18 #include <time.h> 19 using namespace std; 20 21 int a[110]; 22 int main() 23 { 24 //freopen("in.txt","r",stdin); 25 //freopen("out.txt","w",stdout); 26 int n,s; 27 while(scanf("%d%d",&n,&s) == 2) 28 { 29 for(int i = 0;i < n;i++) 30 scanf("%d",&a[i]); 31 sort(a,a+n); 32 int ans = 0; 33 for(int i = 0;i < n-1;i++) 34 ans += a[i]; 35 if(ans <= s)printf("YES\n"); 36 else printf("NO\n"); 37 } 38 return 0; 39 }
DIV2B
1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2014/4/30 19:53:16 4 File Name :E:\2014ACM\Codeforces\CF243\DIV2_B.cpp 5 ************************************************ */ 6 7 #include <stdio.h> 8 #include <string.h> 9 #include <iostream> 10 #include <algorithm> 11 #include <vector> 12 #include <queue> 13 #include <set> 14 #include <map> 15 #include <string> 16 #include <math.h> 17 #include <stdlib.h> 18 #include <time.h> 19 using namespace std; 20 const int MAXN = 110; 21 int a[MAXN][MAXN]; 22 int b[MAXN][MAXN]; 23 24 int main() 25 { 26 //freopen("in.txt","r",stdin); 27 //freopen("out.txt","w",stdout); 28 int n,m; 29 while(scanf("%d%d",&n,&m) == 2) 30 { 31 for(int i = 0;i < n;i++) 32 for(int j = 0;j < m;j++) 33 scanf("%d",&a[i][j]); 34 int tmp = n; 35 if(tmp%2) 36 { 37 printf("%d\n",n); 38 continue; 39 } 40 for(int i = 0;i < n;i++) 41 for(int j = i+1;j < n;j++) 42 { 43 int tt = 1; 44 for(int k = 0;k < m;k++) 45 if(a[i][k] != a[j][k]) 46 { 47 tt = 0; 48 break; 49 } 50 b[i][j] = b[j][i] = tt; 51 } 52 for(int t = 1;t <= n;t++) 53 { 54 int tmp = t; 55 while(tmp < n)tmp *= 2; 56 if(tmp != n)continue; 57 bool flag = true; 58 int mir = t; 59 while(mir != n) 60 { 61 for(int i = 0;i < mir;i++) 62 if(b[i][2*mir-1-i] == 0) 63 { 64 flag = false; 65 break; 66 } 67 if(!flag)break; 68 mir *= 2; 69 } 70 if(flag) 71 { 72 printf("%d\n",t); 73 break; 74 } 75 } 76 } 77 return 0; 78 }
DIV1A
题意:
给出了n(1<=n<=200)的数列a, 让你最多交换k(1<=k<=10)次,使得最大连续子序列的和最大。输出最大的连续子序列和。
因为n比较小,直接暴力枚举区间,然后将这个区间的k个小的,换成比较大的。
代码君:
1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2014/4/27 23:29:36 4 File Name :E:\2014ACM\Codeforces\CF243\A.cpp 5 ************************************************ */ 6 7 #include <stdio.h> 8 #include <string.h> 9 #include <iostream> 10 #include <algorithm> 11 #include <vector> 12 #include <queue> 13 #include <set> 14 #include <map> 15 #include <string> 16 #include <math.h> 17 #include <stdlib.h> 18 #include <time.h> 19 using namespace std; 20 21 const int MAXN = 220; 22 int a[MAXN]; 23 int b[MAXN]; 24 int c[MAXN]; 25 int main() 26 { 27 //freopen("in.txt","r",stdin); 28 //freopen("out.txt","w",stdout); 29 int n,k; 30 while(scanf("%d%d",&n,&k) == 2) 31 { 32 for(int i = 1;i <= n;i++) 33 scanf("%d",&a[i]); 34 int ans = -1000000000; 35 for(int l = 1;l <= n;l++) 36 for(int r = l;r<= n;r++) 37 { 38 int cnt1 = 0; 39 int cnt2 = 0; 40 for(int i = 1;i <= n;i++) 41 { 42 if(i >= l && i <= r) 43 b[cnt1++] = a[i]; 44 else c[cnt2++] = a[i]; 45 } 46 sort(b,b+cnt1); 47 sort(c,c+cnt2); 48 reverse(c,c+cnt2); 49 int tt = min(cnt1,cnt2); 50 tt = min(tt,k); 51 for(int i = 1;i < cnt1;i++) 52 b[i] += b[i-1]; 53 for(int i = 1;i < cnt2;i++) 54 c[i] += c[i-1]; 55 56 57 for(int i = 0;i <= tt;i++) 58 { 59 int num1 = i; 60 int num2 = i; 61 int tmp = b[cnt1-1]; 62 if(num1 > 0)tmp -= b[num1-1]; 63 if(num2 > 0)tmp += c[num2-1]; 64 ans = max(ans,tmp); 65 } 66 67 } 68 printf("%d\n",ans); 69 } 70 return 0; 71 }
DIV1B
给出一个n*m的01矩阵, 让你最多改变k个里面的值(0变1,1变0), 使得0、1的连通分量是矩阵。输出最少步数
1?≤?n,?m?≤?100; 1?≤?k?≤?10
题解:
如果01连通分量是矩形,
那么矩形一定是这样的:
0101010
1010101
0101010
1010101
(上面的01代表子矩阵块)。
也就是每一行要么是相同,要么是相反的。
如果n>k, 肯定有一行是不能改变的,那么枚举这一行,然后其余的要么变相同,要么变相反,看最少的步数。
如果n<k ,那么可以枚举第一列的状态(2^k), 然后其余列变成和第一列相同或者相反。
1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2014/4/29 11:30:04 4 File Name :E:\2014ACM\Codeforces\CF243\B.cpp 5 ************************************************ */ 6 7 #include <stdio.h> 8 #include <string.h> 9 #include <iostream> 10 #include <algorithm> 11 #include <vector> 12 #include <queue> 13 #include <set> 14 #include <map> 15 #include <string> 16 #include <math.h> 17 #include <stdlib.h> 18 #include <time.h> 19 using namespace std; 20 const int MAXN = 110; 21 int a[MAXN][MAXN]; 22 23 int main() 24 { 25 //freopen("in.txt","r",stdin); 26 //freopen("out.txt","w",stdout); 27 int n,m,k; 28 while(scanf("%d%d%d",&n,&m,&k) == 3) 29 { 30 for(int i = 0;i < n;i++) 31 for(int j = 0;j < m;j++) 32 scanf("%d",&a[i][j]); 33 int ans = 100000000; 34 if(n > k) 35 { 36 for(int t = 0;t < n;t++) 37 { 38 int tmp = 0; 39 for(int i = 0;i < n;i++) 40 { 41 int cnt = 0; 42 for(int j = 0;j < m;j++) 43 if(a[i][j] == a[t][j]) 44 cnt++; 45 tmp += min(cnt,m-cnt); 46 } 47 ans = min(tmp,ans); 48 } 49 } 50 else 51 { 52 for(int t = 0;t < (1<<n);t++) 53 { 54 int tmp = 0; 55 for(int j = 0;j < m;j++) 56 { 57 int cnt = 0; 58 for(int i = 0;i < n;i++) 59 if(a[i][j] == ((t>>i)&1)) 60 cnt++; 61 tmp += min(cnt,n-cnt); 62 } 63 ans = min(tmp,ans); 64 } 65 } 66 if(ans <= k)printf("%d\n",ans); 67 else printf("-1\n"); 68 } 69 return 0; 70 }
DIV1C
题意:比较长,自己看题目吧
1?≤?s?≤?3·10^5; 10^3?≤?e?≤?10^4
所以第一个操作最多是300次.
用dp[i][j] 表示a序列消掉了前i个,消了j次,b序列的最小位置。
转移的时候,dp[i][j], 其实就是dp[0][j-1],dp[1][j-1],......dp[i-1][j-1]中最小的,下一个a[i]的位置。
用个数组标记下位置,因为那个最小值是递减的。
1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2014/4/29 22:16:58 4 File Name :E:\2014ACM\Codeforces\CF243\C.cpp 5 ************************************************ */ 6 7 #include <stdio.h> 8 #include <string.h> 9 #include <iostream> 10 #include <algorithm> 11 #include <vector> 12 #include <queue> 13 #include <set> 14 #include <map> 15 #include <string> 16 #include <math.h> 17 #include <stdlib.h> 18 #include <time.h> 19 using namespace std; 20 21 int dp[310][100010]; 22 int a[100010]; 23 int b[100010]; 24 vector<int>vb[100010]; 25 int next[100010]; 26 27 int main() 28 { 29 //freopen("in.txt","r",stdin); 30 //freopen("out.txt","w",stdout); 31 int n,m,s,e; 32 while(scanf("%d%d%d%d",&n,&m,&s,&e) == 4) 33 { 34 for(int i = 0;i < n;i++) 35 scanf("%d",&a[i]); 36 for(int i = 0;i < m;i++) 37 scanf("%d",&b[i]); 38 for(int i = 1; i <= 100000;i++) 39 vb[i].clear(); 40 for(int i = 0;i < m;i++) 41 vb[b[i]].push_back(i); 42 for(int i = 1; i <= 100000;i++) 43 vb[i].push_back(m); 44 int k = s/e; 45 int ans = 0; 46 for(int i = 1;i <= k;i++) 47 { 48 for(int j = 1;j <= 100000;j++) 49 next[j] = vb[j].size() - 1; 50 int mm = m; 51 if(i == 1)mm = -1; 52 for(int j = 0;j < n;j++) 53 { 54 while(next[a[j]] > 0 && vb[a[j]][next[a[j]]-1] > mm) 55 next[a[j]]--; 56 dp[i][j] = vb[a[j]][next[a[j]]]; 57 if(i > 1)mm = min(mm,dp[i-1][j]); 58 if(dp[i][j] < m && j + dp[i][j] + 2 + e*i <= s) 59 ans = max(ans,i); 60 } 61 } 62 printf("%d\n",ans); 63 } 64 return 0; 65 }
DIV1D
题意,给了n个点, 让你求出有多少个平行于坐标轴的正方形,四个点都在给定的点上。
可以使用hash或者二分查找,快速判断一个点是不是存在。
枚举x坐标,如果x的个数<sqrt(n), 那么两重循环枚举这个x的点,确定边长,然后进行hash判断是不是存在。
如果x的个数>=sqrt(n), 那么枚举下所有的点,来确定下边长,然后进行hash判断
1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2014/4/30 18:27:57 4 File Name :E:\2014ACM\Codeforces\CF243\D.cpp 5 ************************************************ */ 6 7 #include <stdio.h> 8 #include <string.h> 9 #include <iostream> 10 #include <algorithm> 11 #include <vector> 12 #include <queue> 13 #include <set> 14 #include <map> 15 #include <string> 16 #include <math.h> 17 #include <stdlib.h> 18 #include <time.h> 19 using namespace std; 20 21 vector<int>vx[100010]; 22 bool has(int x,int y) 23 { 24 if(x > 100000 || y > 100000 || x < 0 || y < 0)return false; 25 return binary_search(vx[x].begin(),vx[x].end(),y); 26 } 27 int main() 28 { 29 //freopen("in.txt","r",stdin); 30 //freopen("out.txt","w",stdout); 31 int n; 32 while(scanf("%d",&n) == 1) 33 { 34 for(int i = 0;i <= 100000;i++) 35 vx[i].clear(); 36 int x,y; 37 for(int i = 0;i < n;i++) 38 { 39 scanf("%d%d",&x,&y); 40 vx[x].push_back(y); 41 } 42 for(int i = 0;i <= 100000;i++) 43 sort(vx[i].begin(),vx[i].end()); 44 int ans = 0; 45 int bd = (int)sqrt(1.0*n); 46 for(int x = 0;x <= 100000;x++) 47 if(vx[x].size()) 48 { 49 if(vx[x].size() < bd) 50 { 51 for(int i = 0;i < vx[x].size();i++) 52 for(int j = i+1;j < vx[x].size();j++) 53 { 54 int d = vx[x][j] - vx[x][i]; 55 if(has(x+d,vx[x][i]) && has(x+d,vx[x][j])) 56 ans++; 57 } 58 } 59 else 60 { 61 for(int xx = x+1;xx <= 100000;xx++) 62 for(int i = 0;i < vx[xx].size();i++) 63 { 64 int yy = vx[xx][i]; 65 int d = xx - x; 66 if(has(x,yy) && has(x,yy+d) && has(xx,yy+d)) 67 ans++; 68 } 69 } 70 } 71 printf("%d\n",ans); 72 } 73 return 0; 74 }
DIV1E
经典的DP题
使用dp[i][j] 表示最多j个不相交区间,最靠左的j个不相交区间的最后一个区间位置是i.
如果dp[i][j] -> dp[ii][j+1]的话,2^( (ii-i)*i ) 这种是横跨的区间,可选可不选。
(ii-i)个区间是最少要选择一个的, 2^(ii-i)-1
然后就可以得出来了。
1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2014/4/28 0:47:23 4 File Name :E:\2014ACM\Codeforces\CF243\E.cpp 5 ************************************************ */ 6 7 #include <stdio.h> 8 #include <string.h> 9 #include <iostream> 10 #include <algorithm> 11 #include <vector> 12 #include <queue> 13 #include <set> 14 #include <map> 15 #include <string> 16 #include <math.h> 17 #include <stdlib.h> 18 #include <time.h> 19 using namespace std; 20 const int MOD = 1e9+7; 21 const int MAXN = 550; 22 int dp[MAXN][MAXN];//dp[i][j]表示有j个不相交区间,最左的最后一个区间的位置是i 23 void Add(int &a,int b) 24 { 25 a += b; 26 while(a >= MOD)a -= MOD; 27 } 28 int two[510*510]; 29 int main() 30 { 31 //freopen("in.txt","r",stdin); 32 //freopen("out.txt","w",stdout); 33 int n,k; 34 two[0] = 1; 35 for(int i = 1;i <= 500*500;i++) 36 two[i] = 2*two[i-1]%MOD; 37 while(scanf("%d%d",&n,&k) == 2) 38 { 39 memset(dp,0,sizeof(dp)); 40 dp[0][0] = 1; 41 for(int i = 0;i < n;i++) 42 for(int j = 0;j < k;j++) 43 if(dp[i][j]) 44 { 45 for(int ii = i+1;ii <= n;ii++) 46 { 47 long long tmp = two[i*(ii - i)]; 48 tmp = tmp*(two[ii-i]-1)%MOD; 49 Add(dp[ii][j+1],tmp*dp[i][j]%MOD); 50 } 51 } 52 int ans = 0; 53 for(int i = 0;i <= n;i++) 54 Add(ans,(long long)dp[i][k]*two[i*(n-i)]%MOD); 55 printf("%d\n",ans); 56 } 57 return 0; 58 }