首页 > 代码库 > CodeForces Round #286 Div.2
CodeForces Round #286 Div.2
A. Mr. Kitayuta‘s Gift (枚举)
题意:
给一个长度不超过10的串,问能否通过插入一个字符使得新串成为回文串。
分析:
因为所给的串很多,所以可以枚举 “在哪插入” 和 “插入什么”,写一个二重循环枚举新串,判断是否为回文串。时间复杂度为O(n3)
还可只枚举插入位置(在那个位置用一个特殊字符表示),在判断的时候,如果遇到特殊字符,则所插入的字符一定为镜像的字符。
1 #include <cstdio> 2 #include <cstring> 3 4 char s[15], s1[15]; 5 int l; 6 7 bool judge() 8 { 9 for(int i = 0; i < (l+1)/2; ++i)10 if(s1[i] == 0) s1[i] = s1[l-i];11 else if(s1[l-i] == 0) s1[l-i] = s[i];12 else if(s1[i] != s1[l-i]) return false;13 14 return true;15 }16 17 int main()18 {19 scanf("%s", s);20 l = strlen(s);21 bool flag = false;22 for(int pos = 0; pos <= l; ++pos)23 {//枚举所加入字符的位置,s1为得到的新串24 int i;25 for(i = 0; i < pos; ++i) s1[i] = s[i];26 s1[i++] = 0;27 for(; i <= l; ++i)s1[i] = s[i-1];28 if(judge()) { flag = true; break; }29 }30 31 if(!flag) puts("NA");32 else33 {34 for(int i = 0; i <= l; ++i)35 if(s1[i] == 0) printf("a");36 else printf("%c", s1[i]);37 }38 39 return 0;40 }
B. Mr. Kitayuta‘s Colorful Graph (并查集)
题意:
有一个多种颜色的无向图,给出每条边的两个顶点以及该边的颜色。
然后有若干次询问,每次询问两点间共有多少种颜色的通路。
分析:
这道题可以理解为二维的并查集。如果没有颜色的区分,可以判断两点是否连通。
现在给边染上颜色,则我们可以分开处理。最后在询问的时候枚举所有颜色,判断两点是否连通。
1 #include <cstdio> 2 #include <vector> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 7 const int maxn = 100 + 10; 8 9 int G[maxn][maxn];10 int n, m;11 int p[maxn][maxn];12 //找颜色为color的边中,x的父节点13 int findp(int color, int x) { return x == p[color][x] ? x : p[color][x] = findp(color, p[color][x]); }14 15 struct Edge16 {17 int u, v;18 Edge(int u=0, int v=0):u(u), v(v) {}19 };20 21 vector<Edge> edges[maxn];22 23 int main()24 {25 //freopen("in.txt", "r", stdin);26 int n, m, Mc = 0;27 scanf("%d%d", &n, &m);28 //并查集初始化29 for(int i = 1; i <= m; ++i)30 for(int j = 1; j <= n; ++j)31 p[i][j] = j;32 33 for(int i = 0; i < m; ++i)34 {35 int a, b, c;36 scanf("%d%d%d", &a, &b, &c);37 Mc = max(Mc, c);38 int pa = findp(c, a);39 int pb = findp(c, b);40 if(pa != pb) p[c][pa] = pb;41 }42 43 int Q;44 scanf("%d", &Q);45 for(int i = 0; i < Q; ++i)46 {47 int u, v, cnt = 0;48 scanf("%d%d", &u, &v);49 for(int c = 1; c <= Mc; ++c) //枚举所有颜色50 if(findp(c, u) == findp(c, v))51 cnt++;52 printf("%d\n", cnt);53 }54 55 return 0;56 }
C. Mr. Kitayuta, the Treasure Hunter (DP)
题意:
参见原文吧,=_=||
Mr. Kitayuta, the Treasure Hunter
分析:
设dp(i, j)表示跳到第i个岛步长为j,wi表示第i个岛的宝石数,最大能取到的宝石数。
状态转移方程为 dp(i, j) = wi + max{dp(i+j-1, j-1), dp(i+j, j), dp(i+j+1, j+1)}
上式是从后往前推的,最终答案是dp(d, d)。
从前往后推也是一样的,不过要维护一个最大值。
还有一个很严重的问题就是:30000×30000的空间太大了!
再深入分析,其实步长的变化范围没有3w那么大。
假设每一步步长为前面步长加一,可以求出最大步长。类似地,求出最小步长。
假设d=1,最大步长不会超过245 + d,因为
同样的,如果d≤244,则最小步长为0.
如果d≥245,
所以,最小步长不会小于max{0, d - 245}.
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 5 int max3(int a, int b, int c) 6 { return max(max(a, b), c); } 7 8 int w[70000], dp[65000][500]; 9 10 int main()11 {12 //freopen("in.txt", "r", stdin);13 14 int n, d;15 scanf("%d%d", &n, &d);16 for(int i = 0; i < n; ++i)17 {18 int x;19 scanf("%d", &x);20 w[x]++;21 }22 23 int maxp, minp = 1;24 for(int n = 0; ; n++) if(d*(n+1)+n*(n+1)/2 >= 30000)25 {26 maxp = d + n; //最大步长27 break;28 }29 for(int n = 0; d >= 245; n++) if(d*(n+1)-n*(n+1)/2 >= 30000)30 {31 minp = d - n; //最小步长32 break;33 }34 35 for(int x = 30000; x >= d; --x)36 for(int l = minp; l <= maxp; ++l)37 dp[x][l-minp+1] = w[x] + max3(dp[x+l][l-minp+1], dp[x+l+1][l+2-minp], dp[x+l-1][l-minp]);38 39 printf("%d\n", dp[d][d+1-minp]);40 41 return 0;42 }
CodeForces Round #286 Div.2