【A题】
类型:模拟题
注意点:
1、用字符串存储数字,存储字符串长度应大于1000,因为含1000字符的字符串实际占用空间有1001个字节。
2、计算加法从最低位开始,而最低位对应字符串末尾,可先逆转字符串,即“123”变为“321”,再从第0位开始计算。
3、假定两个字符串的其中的最大长度为L,那么答案字符串的长度可能是L+1,如“1”和“9”,其和为“10”。
4、避免出现无效的前导“0”,如结果不可能是“0123”。
参考程序:
/* * Author: Wu Hanzhou * Time: 2014/4/11 * Language: C++ * Role: Check for SWJTU-CPC-2014 */ #include<stdio.h> #include<string.h> #include<assert.h> #define maxN (1024) char A[maxN], B[maxN], C[maxN]; void gao() { int i, j = 0, la = strlen(A), lb = strlen(B), lc = 0; assert(la <= 1000 && lb <= 1000); memset(C, 0, sizeof(C)); strrev(A); strrev(B); for(i = 0; i < la || i < lb; i ++) { if( i < la && i < lb ) { C[lc] = '0' + ((A[i] - '0' + B[i] - '0' + j) % 10); j = ((A[i] - '0' + B[i] - '0' + j) / 10); lc ++; } else { if( i < la ) { C[lc] = '0' + ((A[i] - '0' + j) % 10); j = ((A[i] - '0' + j) / 10); lc ++; } else { C[lc] = '0' + ((B[i] - '0' + j) % 10); j = ((B[i] - '0' + j) / 10); lc ++; } } } C[lc] = '0' + j; lc ++; while( (lc - 1 > 0) && (C[lc - 1] == '0') ) lc --; C[lc] = 0; strrev(C); } int main() { int k, nt; scanf("%d", &nt); for(k = 0; k < nt; k ++) { scanf("%s %s", A, B); if( k ) printf("\n"); printf("Case %d:\n", k + 1); printf("%s + %s = ", A, B); gao(); printf("%s\n", C); } return 0; }
类型:最长公共子序列 (Longest Common Subsequence, LCS)
注意点:
1、请保证存储空间超过1000,有些同学一直是开到1000,这是没有理解字符串如何存储。
2、如果 S[ i ] = S[ j ],那么 DP[ i ][ j ] = DP[ i - 1 ][ j - 1 ] + 1;否则,DP[ i ][ j ] = max(DP[ i-1 ][ j ], DP[ i ][ j-1 ])。
参考代码:
/* * Author: Wu Hanzhou * Time: 2014/4/11 * Language: C++ * Role: Check for SWJTU-CPC-2014 */ #include<stdio.h> #include<string.h> #include<assert.h> #define maxN (1024) char A[maxN], B[maxN]; short dp[maxN][maxN]; int gao() { int i, j, la = strlen(A), lb = strlen(B); assert(la <= 1000 && lb <= 1000); for(i = 0; i < la; i ++) { for(j = 0; j < lb; j ++) { if( i == 0 || j == 0 ) { if( A[i] == B[j] ) dp[i][j] = 1; else { if( i == 0 ) dp[i][j] = dp[i][j - 1]; else dp[i][j] = dp[i - 1][j]; } } else { if( A[i] == B[j] ) dp[i][j] = 1 + dp[i - 1][j - 1]; else { dp[i][j] = dp[i - 1][j]; if( dp[i][j] < dp[i][j - 1] ) dp[i][j] = dp[i][j - 1]; } } } } return (int)dp[la - 1][lb - 1]; } int main() { while( scanf("%s %s", A, B) == 2 ) printf("%d\n", gao()); return 0; }
类型:素数筛法+二分
基本思路:先筛选出给定范围内的所有素数,然后计算连续区间内的素数和,判断其是否也为素数,如果是,则标记为可写成连续素数的和,否则不是。
参考代码:
/* * Author: Wu Hanzhou * Time: 2014/4/11 * Language: C++ * Role: Check for SWJTU-CPC-2014 */ #include<stdio.h> #include<string.h> #include<assert.h> #define maxN (500000) bool vst[maxN]; int prime[maxN]; int total_prime = 0; void get_prime() { int i, j, up = maxN; memset(vst, 0, sizeof(vst)); prime[total_prime ++] = 2; for(i = 3; i < up; i += 2) { if( vst[i] == false ) { prime[total_prime ++] = i; for(j = i << 1; j < up; j += i) vst[j] = true; } } //printf("total_prime = %d, (%d)\n", total_prime, prime[total_prime - 1]); } long long sum[50000]; bool sgn[maxN]; void gao() { int i, j, l, r, m, t; long long tmp; sum[0] = prime[0]; for(i = 1; i < total_prime; i ++) sum[i] = sum[i - 1] + prime[i]; memset(sgn, 0, sizeof(sgn)); for(i = 1; i < total_prime && sum[i] < maxN; i ++) if( vst[sum[i]] == false ) sgn[sum[i]] = true; for(i = 1; i < total_prime; i ++) { l = i + 1, r = total_prime - 1; t = -1; tmp = sum[i - 1]; while( l <= r ) { m = (l + r) >> 1; if( sum[m] - tmp > maxN ) r = m - 1; else l = m + 1, t = m; } if( t != -1 ) { for(j = i + 1; j <= t; j ++) if( vst[sum[j] - tmp] == false ) sgn[sum[j] - tmp] = true; } } j = 0; for(i = 0; i < total_prime; i ++) if( sgn[ prime[i] ] ) prime[j ++] = prime[i]; total_prime = j; for(i = maxN - 1; i >= 0 && total_prime > 0; total_prime --) while( i >= prime[total_prime - 1] ) prime[i --] = prime[total_prime - 1]; while( i >= 0 ) prime[i --] = 0; } int main() { //#define LOCAL_JUDGE #ifdef LOCAL_JUDGE freopen("data.in", "r", stdin); freopen("data.out", "w", stdout); #endif get_prime(); gao(); int N; while( scanf("%d", &N) == 1 ) { assert(N > 0 && N < 500000); printf("%d\n", prime[N]); } #ifdef LOCAL_JUDGE fclose(stdin); fclose(stdout); #endif return 0; }
类型:水题
注意点:
1、不足3位补0。
参考代码:
/* * Author: Wu Hanzhou * Time: 2014/4/11 * Language: C++ * Role: Check for SWJTU-CPC-2014 */ #include<stdio.h> #include<string.h> #include<assert.h> #define maxN (500000) int main() { //#define LOCAL_JUDGE #ifdef LOCAL_JUDGE freopen("data.in", "r", stdin); freopen("data.out", "w", stdout); #endif int A, B, C; while( scanf("%d %d", &A, &B) == 2 ) { assert(A >= 0 && A <= 10000 && B >= 0 && B <= 10000); if( A == 0 && B == 0 ) break; C = A % 1000; while( -- B ) C = (C * A) % 1000; printf("%03d\n", C); } #ifdef LOCAL_JUDGE fclose(stdin); fclose(stdout); #endif return 0; }
类型:水题
参考代码:
/* * Author: Wu Hanzhou * Time: 2014/4/11 * Language: C++ * Role: Check for SWJTU-CPC-2014 */ #include<stdio.h> #include<string.h> #include<assert.h> #define maxN (1024) char marry[maxN], carry[maxN]; int main() { //#define LOCAL_JUDGE #ifdef LOCAL_JUDGE freopen("data.in", "r", stdin); freopen("data.out", "w", stdout); #endif while( scanf("%s %s", marry, carry) == 2 ) { int lm = strlen(marry), lc = strlen(carry); assert(lm == lc); int wins_marry = 0, wins_carry = 0; for(int i = 0; i < lm; i += 2) { if( marry[i] == '[' ) { if( carry[i] == '8' ) wins_marry ++; if( carry[i] == '[' ) ; if( carry[i] == '(' ) wins_carry ++; } if( marry[i] == '(' ) { if( carry[i] == '[' ) wins_marry ++; if( carry[i] == '(' ) ; if( carry[i] == '8' ) wins_carry ++; } if( marry[i] == '8' ) { if( carry[i] == '(' ) wins_marry ++; if( carry[i] == '8' ) ; if( carry[i] == '[' ) wins_carry ++; } } printf("%s\n", wins_marry > wins_carry ? "Marry" : \ (wins_marry == wins_carry ? "Equal" : "Carry") ); } #ifdef LOCAL_JUDGE fclose(stdin); fclose(stdout); #endif return 0; }
类型:数据结构 (RMQ 或者 线段树等)
基本思路:缩点 + RMQ 静态查询或者线段树动态查询
参考代码:
/* * Author: Wu Hanzhou * Time: 2014/4/11 * Language: C++ * Role: Check for SWJTU-CPC-2014 */ #include<stdio.h> #include<string.h> #include<assert.h> #include<iostream> #include<algorithm> using namespace std; const int maxn = 100000 + 2; struct node { int val; int low, high; }; node A[maxn]; int nA, N, Q; node Tree[maxn << 2]; int Build_Tree(int left, int right, int idx) { Tree[idx].low = left; Tree[idx].high = right; if(left == right) return (Tree[idx].val = A[left].high - A[left].low + 1); int mid = (left + right) >> 1; int _left = Build_Tree(left, mid, idx << 1); int _right = Build_Tree(1 + mid, right, 1 + (idx << 1)); return (Tree[idx].val = max(_left, _right)); } int Query_Tree(int left, int right, int idx) { if(left > right) return 0; if(left == Tree[idx].low && right == Tree[idx].high) return Tree[idx].val; int mid = (Tree[idx].low + Tree[idx].high) >> 1; if(right <= mid) return Query_Tree(left, right, idx << 1); if(mid < left) return Query_Tree(left, right, 1 + (idx << 1)); return max(Query_Tree(left, mid, idx << 1), Query_Tree(1 + mid, right, 1 + (idx << 1))); } int bs(node A[], int low, int high, int &key) { int mid; while(low <= high) { mid = (low + high) >> 1; if(A[mid].low <= key && A[mid].high >= key) return mid; if(A[mid].low > key) high = mid - 1; else low = mid + 1; } return -1; } int main() { while( scanf("%d", &N) == 1 && N ) { scanf("%d", &Q); nA = 1; int val; for(int i = 1; i <= N; ++i) { scanf("%d", &val); if(i == 1) { A[nA].val = val; A[nA].low = A[nA].high = i; } else { if(val == A[nA].val ) A[nA].high = i; else { ++nA; A[nA].val = val; A[nA].low = A[nA].high = i; } } } Build_Tree(1, nA, 1); int x, y, fx, fy; for(int i = 0; i < Q; ++i) { scanf("%d%d", &x, &y); fx = bs(A, 1, nA, x); fy = bs(A, 1, nA, y); if(fx == fy) printf("%d\n", y - x + 1); else printf("%d\n", max( - x + A[fx].high + 1, \ max( - A[fy].low + y + 1, Query_Tree(fx + 1, fy - 1, 1)))); } } return 0; }
类型:简单题
基本思路:直接判断第N-1天所能学到的单元数即可,这是因为第K+1天能看到单元数不会少于第K天。
参考代码:
/* * Author: Wu Hanzhou * Time: 2014/4/11 * Language: C++ * Role: Check for SWJTU-CPC-2014 */ #include<stdio.h> #include<string.h> #include<assert.h> int main() { int nt, idx = 0; scanf("%d", &nt); assert(nt <= 10000); int i, tmp, N; while( (nt --) > 0 ) { scanf("%d", &N); //assert(N >= 1 && N <= 1000000007); tmp = 0, i = N - 1; if( i >= 30 ) tmp ++; if( i >= 15 ) tmp ++; if( i >= 7 ) tmp ++; if( i >= 4 ) tmp ++; if( i >= 2 ) tmp ++; if( i >= 1 ) tmp ++; if( i >= 0 ) tmp ++; printf("Case #%d: %d\n", ++idx, tmp); } return 0; }
类型:枚举+推导
基本思路:
1、其实如果你先去做I题,可以发现 p = 1, 2, 3时都是有限的,4是无限的。
2、现在我们来证明3个命题:
定义:S(p) 表示回文长度为p的所有满足条件的字符串长度最大的字符串的长度。
(1) 如果 S(p) 无限,那么对于任意 k > 0,有 S(p + 2 * k) 也是无限。
证明:假设对应S(p)的无限长的某个字符串是 T(p),不是一般性,令T(p)的某一前缀是回文串且长度为p,显然可以在T(p)的前面增加一个字符,使得T(p)的前缀是回文串且长度为p+2,此时成功构造了 S(p + 2),由于 S(p) 无限,所以S(p + 2) 也无限长。以此类推,可证 S(p + 2 * k) 也是无限。
(2) 如果S(p) 无限,那么形同 "aaa...aaa" (长度为p) 或 "bbb...bbb" (长度为p) 一定可以存在某个合法的 T(p) 中,而且只可能是 T(p) 的前缀。
证明:(I) 假设存在这样的"aaa...aaa" (长度为p) 或 "bbb...bbb" 是 T(p) 的非前缀,根据容斥原理,显然 "aaa...aaa" 或 "bbb...bbb" 的左侧或者右侧存在一个字符与"a" 或者 "b" 相等,这样它的最大回文长度为 p+1,与长度为p矛盾,故如果存在,则"aaa...aaa" 或 "bbb...bbb" 一定是 T(p) 的前缀。(II) 显然一定存在这样的 T(p) 不包含"aaa...aaa" (长度为p) 或 "bbb...bbb" ,而我们总可以在它的前面补足"a" 或"b",使得"aaa...aaa" 或 "bbb...bbb" 是它的前缀,而且仍然是合法的字符串。结合(I)、(II),命题得证。
(3) 如果S(p) 无限,那么S(p + 1) 无限。
证明:如果S(p) 无限,那么可以在包含形同 "aaa...aaa" (长度为p) 或 "bbb...bbb" (长度为p) 的T(p)的前面添加1个"a"或"b",使得S(p+1) 无限。
参考程序:
/* * Author: Wu Hanzhou * Time: 2014/4/11 * Language: C++ * Role: Check for SWJTU-CPC-2014 */ #include<stdio.h> #include<string.h> #include<assert.h> int main() { int p; while( scanf("%d", &p) == 1 ) { assert(p >= 1 && p <= 100); switch( p ) { case 1: puts("2"); break; case 2: puts("4"); break; case 3: puts("8"); break; default: puts("Unlimited!"); break; } } return 0; }
【I题】
类型:搜索题 (DFS)
参考代码:
/* * Author: Wu Hanzhou * Time: 2014/4/11 * Language: C++ * Role: Check for SWJTU-CPC-2014 */ #include<stdio.h> #include<string.h> #include<assert.h> const int maxN = 200 + 2; const int up = 200; const int p = 5; char str[maxN]; bool judge(int c, int NN) { int tot = 1; for(int i = c - 1, j = c + 1; i >= 0 && j <= NN; i --, j ++) if( str[i] == str[j] ) tot += 2; else break; if( tot > p ) return true; if( c + 1 <= NN && str[c] == str[c + 1] ) { tot = 2; for(int i = c - 1, j = c + 2; i >= 0 && j <= NN; i --, j ++) if( str[i] == str[j] ) tot += 2; else break; if( tot > p ) return true; } return false; } bool dfs(int idx) { if( idx == 200 ) return true; bool chk = true; str[idx] = 'a'; for(int i = 0; i <= idx && chk; i ++) if( judge(i, idx) ) chk = false; if( chk ) { chk = dfs(idx + 1); if( chk ) return true; } chk = true; str[idx] = 'b'; for(int i = 0; i <= idx && chk; i ++) if( judge(i, idx) ) chk = false; if( chk ) { chk = dfs(idx + 1); if( chk ) return true; } return false; } int main() { freopen("data.in", "r", stdin); freopen("data.out", "w", stdout); dfs(0); int n; str[200] = 0; //printf("%s\n", str); // aaaaa baab babaaab babaaab babaaab babaaab babaaab babaaab babaaab babaaab babaaab babaaab // babaaab babaaab babaaab babaaab babaaab babaaab babaaab babaaab babaaab babaaab babaaab // babaaab babaaab babaaab babaaab babaaab babaaab ba while( scanf("%d", &n) == 1 ) { assert(n > 0 && n < 200); printf("%c\n", str[n - 1]); } return 0; }