题目一: Buy low, buy lower
** Description: 最长下降子序列中不同的序列有多少个?
** Algorithm: DP + BIGN
** Analysis: BASIC b[i] = b[j]+1 | a[j] > a[i] and b[j]+1 > b[i], 1 <= j < i
如果计算重复,则
cnt[i] += cnt[j] | a[j] > a[i] and b[j]+1 = b[i]. 1 <= j < i;
cnt[i] = MAX(1);
** Special Test:9 7 5 8 5 1 Dp 1 2 3 2 3 4 Num 1 1 1 1 2 2
对于第一个出现的5和第二个5,他们的dp一样,但是num却不一样。
这里我们可以取最后一个5,原因如下:对于非最后一个5的序列,最后一个5,一定可以取得。
例如对于第二个5,第一个5的9 7 5序列,第二个5同样可以取得。而且后面的5可能会有更多的取法,
例如上例中的第二个5,还可以获得9 8 5这个序列。所以我们这里,最后1对应的num应该是2
#include <stdio.h> #include <string.h> #define MAXN 5010 #define BASE 100000000 #define MAXL 100 struct BIGN { int L; int a[MAXL]; BIGN() { L = 1; memset(a,0,sizeof(a)); } void display() { printf("%d", a[L]); for (int i = L-1; i >= 1; i--) printf("%08d", a[i]); } void plus (BIGN c) { if (c.L > L) L = c.L; for (int i = 1; i <= L; i++) { a[i] += c.a[i]; if (a[i] >= BASE) { a[i+1] += a[i] / BASE; a[i] %= BASE; } } if (a[L+1]) L++; } }; int n, i, j; int a[MAXN], b[MAXN]; BIGN cnt[MAXN]; int main(){ freopen("buylow.in", "r", stdin); freopen("buylow.out", "w", stdout); scanf("%d", &n); for (i = 1; i <= n+1; i++) { if (i <= n) scanf("%d", &a[i]); else a[i] = 0; b[i] = 1; bool flag = false; for (j = i-1; j >= 1; j--) if (a[j] > a[i] && b[j]+1 > b[i]) b[i] = b[j]+1; int y = -1; for (j = i-1; j >= 1; j--) /*前两个条件为递推的累加,后一个为去掉重复(a[j]==j,只取最近一个)*/ if (a[j] > a[i] && b[j]+1 == b[i] && (y < 0 || a[j] < y)) { y = a[j]; cnt[i].plus(cnt[j]); flag = true; } if (!flag) cnt[i].a[1] = 1; } printf("%d ", b[n+1]-1); cnt[n+1].display(); printf("/n"); return 0; }
题目二:The Primes
很麻烦的一道题目,花了好久才不TLE,不想再写第二遍了!
/* ID: zhangji42 PROG: prime3 LANG: C++ */ #include <iostream> #include <vector> #include <algorithm> #include <string> #include <string.h> #include <stdio.h> #include <sstream> #include <time.h> using namespace std; const int maxp = 100000; struct type { int num, n[6]; }; bool h[maxp] = {0}; bool pri[10][10][10][10][10]={0}; int len = 0, sum, first; string s[200]; int f, mid; type n1, n2, n3, n4, n5, n6; type type1[10][100];//means all the primes and all odd digits type type2[10][100];//not zero type type4[10][100]; type type3[10][10][10][100]; int main() { freopen("prime3.in", "r" ,stdin); freopen("prime3.out", "w", stdout); void makeprime(); void work(); int get(int,int); scanf("%d%d", &sum, &first); makeprime(); work(); sort(s, s+len); for (int i = 0; i < len; i++) { if (i) cout << endl; cout << s[i]; } return 0; } int get(int n, int k) { if (k == 1) return n/10000; if (k == 2) return (n/1000) % 10; if (k == 3) return (n/100) % 10; if (k == 4) return (n/10) % 10; if (k == 5) return n % 10; } void makeprime() { for (int i = 2; i < maxp; i++) if (!h[i]) { for (int j = i+i; j < maxp; j += i) h[j] = 1; if (i <= 10000) continue; bool odd = true, zero = false; type tmp; tmp.num = i; int ssum = 0, ii = i; for (int j = 1; j <= 5; j++) { tmp.n[j] = get(i, j); if (tmp.n[j] % 2== 0) odd = false; if (!tmp.n[j]) zero = true; ssum += ii % 10; ii /= 10; } if (ssum != sum) { h[i] = 1; continue; } pri[get(i, 1)][get(i, 2)][get(i, 3)][get(i, 4)][get(i, 5)] = 1; //printf("%d/n", i); if (tmp.n[1] == first) { type4[tmp.n[5]][++type4[tmp.n[5]][0].num] = tmp; if (!zero) type2[tmp.n[5]][++type2[tmp.n[5]][0].num] = tmp; } if (odd) type1[tmp.n[5]][++type1[tmp.n[5]][0].num] = tmp; type3[tmp.n[1]][tmp.n[3]][tmp.n[5]][++type3[tmp.n[1]][tmp.n[3]][tmp.n[5]][0].num] = tmp; } } void work() { int i, j, k, i1, i2, i3, ff, ii, jj; int left1, left2, left3, left4, row2, row3, row4, col2, col3, col4; for (ff = 0; ff < 5; ff++) { f = ff*2+1; for (i = 1; i <= type1[f][0].num; i++) for (j = 1; j <= type1[f][0].num; j++) { n1 = type1[f][i]; n2 = type1[f][j]; ii = n1.n[1];jj = n2.n[1]; for (i2 = 1; i2 <= type4[f][0].num; i2++) { n4 = type4[f][i2]; mid = n4.n[3]; for (k = 1; k <= type3[ii][mid][jj][0].num; k++) { n6 = type3[ii][mid][jj][k]; for (i1 = 1; i1 <= type2[ii][0].num; i1++) { n3 = type2[ii][i1]; left1 = sum - n3.n[2] - n4.n[2] - n6.n[4] - n2.n[2]; if (left1 < 0 || left1 >= 10) continue; left3 = sum - n3.n[4] - n6.n[2] - n4.n[4] - n2.n[4]; if (left3 < 0 || left3 >= 10) continue; if (!pri[n3.n[2]][n4.n[2]][left1][n6.n[4]][n2.n[2]]) continue;//row2 if (!pri[n3.n[4]][n6.n[2]][left3][n4.n[4]][n2.n[4]]) continue;//row4 for (i3 = 1; i3 <= type2[jj][0].num; i3++) { n5 = type2[jj][i3]; left2 = sum - n5.n[2] - n4.n[2] - n6.n[2] - n1.n[2]; if (left2 < 0 || left2 >= 10) continue; left4 = sum - n5.n[4] - n6.n[4] - n4.n[4] - n1.n[4]; if (left4 < 0 || left4 >= 10) continue; if (!pri[n3.n[3]][left2][n4.n[3]][left4][n2.n[3]]) continue;//row3 if (!pri[n5.n[2]][n4.n[2]][left2][n6.n[2]][n1.n[2]]) continue;//col2 if (!pri[n5.n[3]][left1][n4.n[3]][left3][n1.n[3]]) continue;//col3 if (!pri[n5.n[4]][n6.n[4]][left4][n4.n[4]][n1.n[4]]) continue;//col4 /*把方案整个保存到一个字符串中,用了字符串文件流*/ ostringstream ss; ss<<n5.num<<'/n' <<n3.n[2]<<n4.n[2]<<left1<<n6.n[4]<<n2.n[2]<<'/n' <<n3.n[3]<<left2<<n4.n[3]<<left4<<n2.n[3]<<'/n' <<n3.n[4]<<n6.n[2]<<left3<<n4.n[4]<<n2.n[4]<<'/n' <<n1.num<<'/n'; s[len]=ss.str(); len++; } } } } } } } /* Test 1: TEST OK [0.011 secs, 6040 KB] Test 2: TEST OK [0.011 secs, 6040 KB] Test 3: TEST OK [0.022 secs, 6040 KB] Test 4: TEST OK [0.043 secs, 6040 KB] Test 5: TEST OK [0.032 secs, 6040 KB] Test 6: TEST OK [0.076 secs, 6040 KB] Test 7: TEST OK [0.076 secs, 6040 KB] Test 8: TEST OK [0.130 secs, 6040 KB] Test 9: TEST OK [0.108 secs, 6040 KB] Test 10: TEST OK [0.184 secs, 6040 KB] */
题目三:Street Race
** Description: 第一问为求有向图的割,第二问为求无向图的割
** Algorithm: DFS
** Analysis: 完全图的3个性质:
1.任意一个点从起点可达;
2.任意一个点可到达终点;
3.终点出度为0;
第一问的答案保证了没有从分割1到分割2的边;
第二问的答案同时要保证没有分割2到分割1的边;
故第二问可以在第一问的基础上展开。同时也可以保证分割的两部分都是完全图!
但是貌似数据里面没有判断第二问的分割点没有自环边。
交上去发现有这种数据,但是按照可以的来算的
/* ID: zhangji42 TASK: race3 LANG: C++ */ #include <stdio.h> #include <string.h> //#include <vector> #include <iostream> #define MAXN 60 using namespace std; int f[MAXN][MAXN], vis[MAXN]; //vector <int> ans1; //vector <int> ans2; int ans1[MAXN]={0}; int s1 = 0; int ans2[MAXN]={0}; int s2 = 0; int i, n; bool DFS(int x) { if (x == n) return true; for (int i = 1; i <= n; i++) if (!vis[i] && f[x][i]) { vis[i] = 1; if (DFS(i)) return true; } return false; } bool IsCut(int x) { for (int i = 0; i <= n; i++) if (f[x][i]) { if (vis[i] == 1) return true; else if(vis[i] != 2) { vis[i] = 2; if (IsCut(i)) return true; } } return false; } int main(){ freopen("race3.in", "r", stdin); freopen("race3.out", "w", stdout); n = 0; do { int _u; scanf("%d", &_u); if (_u == -1) break; while (_u != -2) { f[n][_u] = 1; // if (n == _u) ans2[n] = -1; scanf("%d", &_u); } n++; } while (1); n--; memset(vis,0,sizeof(vis)); for (i = 1; i < n; i++) { memset(vis,0,sizeof(vis)); vis[0] = 1; vis[i] = 2; if (!DFS(0)) { ans1[i] = 1, s1++; if (ans2[i] >= 0 && !IsCut(i)) ans2[i] = 1, s2++; } } printf("%d", s1); for (i = 1; i <= n ; i++) if (ans1[i]==1) printf(" %d", i); printf("/n%d", s2); for (i = 1; i <= n; i++) if (ans2[i]==1) printf(" %d", i); printf("/n"); return 0; } /********************************************** ** Description: 第一问为求有向图的割,第二问为求无向图的割 ** Algorithm: DFS ** Analysis: 完全图的3个性质: 1.任意一个点从起点可达; 2.任意一个点可到达终点; 3.终点出度为0; 第一问的答案保证了没有从分割1到分割2的边; 第二问的答案同时要保证没有分割2到分割1的边; 故第二问可以在第一问的基础上展开。同时也可以保证分割的两部分都是完全图! 但是貌似数据里面没有判断第二问的分割点没有自环边。 ***********************************************/
题目四: Letter Game
** Description: 这道题目关键是理解题意:
** 正确的理解应是 在给定的DICT中找出一个或两个单词的组合,
满足各字母出现的次数不多于给定的输入的字符串中各字母的个数
** Analysis: 一开始可能会害怕枚举,应为感觉数据范围好大的,但是可以经过初步删选,得到的只是很小的一部分
两个的情况只要枚举一下就可以了
** NOTE: 由于要按照字典序,可以把最后一个设为空串
#include <algorithm> #include <stdio.h> #include <string.h> #include <iostream> #define MAXM 1000 using namespace std; const int v[26] = {2,5,4,4,1,6,5,5,1,7,6,3,5,2,3,5,7,2,1,2,4,6,6,7,5,7}; char s[10], word[MAXM][10]; int t[26], pt[26], f[MAXM][MAXM], d[MAXM]; int i, j; int check(int i, int j) { memcpy(pt,t,sizeof(t)); int p; for (p = 0; word[i][p]; p++) if (--pt[word[i][p]-'a'] < 0) return -1; for (p = 0; word[j][p]; p++) if (--pt[word[j][p]-'a'] < 0) return -1; return d[i]+d[j]; } int main(){ FILE *fin = fopen("lgame.in", "r"); FILE *dict = fopen("lgame.dict", "r"); FILE *fout = fopen("lgame.out", "w"); fscanf(fin,"%s", s); memset(t,0,sizeof(t)); for (i = 0; s[i]; i++) t[s[i]-'a']++; int ans = 0, m = 0, sum = 0; while (fscanf(dict,"%s", s) && s[0] != '.') { memcpy(pt,t,sizeof(t)); sum = 0; for (i = 0; s[i]; i++) { if (--pt[s[i]-'a'] < 0) break; sum += v[s[i]-'a']; } if (s[i]) continue; strcpy(word[m], s); d[m++] = sum; } word[m][0] = '/0'; d[m++] = 0; for (i = 0; i < m-1; i++) for (j = i+1; j < m; j++) { f[i][j] = check(i, j); if (f[i][j] > ans) ans = f[i][j]; } fprintf(fout, "%d/n", ans); for (i = 0; i < m-1; i++) for (j = i+1; j < m; j++) if (f[i][j] == ans) if (j == m-1) fprintf(fout, "%s/n", word[i]); else fprintf(fout, "%s %s/n", word[i], word[j]); return 0; }