題目一: 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><br />#include <string.h><br />#define MAXN 5010<br />#define BASE 100000000<br />#define MAXL 100<br />struct BIGN {<br />int L;<br />int a[MAXL];<br />BIGN() {<br />L = 1;<br />memset(a,0,sizeof(a));<br />}<br />void display() {<br />printf("%d", a[L]);<br />for (int i = L-1; i >= 1; i--) printf("%08d", a[i]);<br />}<br />void plus (BIGN c) {<br />if (c.L > L) L = c.L;<br />for (int i = 1; i <= L; i++) {<br />a[i] += c.a[i];<br />if (a[i] >= BASE) {<br />a[i+1] += a[i] / BASE;<br />a[i] %= BASE;<br />}<br />}<br />if (a[L+1]) L++;<br />}<br />};</p><p>int n, i, j;<br />int a[MAXN], b[MAXN];<br />BIGN cnt[MAXN];<br />int main(){<br />freopen("buylow.in", "r", stdin);<br />freopen("buylow.out", "w", stdout);<br />scanf("%d", &n);<br />for (i = 1; i <= n+1; i++)<br />{<br />if (i <= n) scanf("%d", &a[i]); else a[i] = 0;<br />b[i] = 1;<br />bool flag = false;<br />for (j = i-1; j >= 1; j--)<br />if (a[j] > a[i] && b[j]+1 > b[i])<br />b[i] = b[j]+1;<br />int y = -1;<br />for (j = i-1; j >= 1; j--)<br />/*前兩個條件為遞推的累加,後一個為去掉重複(a[j]==j,只取最近一個)*/<br />if (a[j] > a[i] && b[j]+1 == b[i] && (y < 0 || a[j] < y))<br />{<br />y = a[j];<br />cnt[i].plus(cnt[j]);<br />flag = true;<br />}<br />if (!flag) cnt[i].a[1] = 1;<br />}<br />printf("%d ", b[n+1]-1); cnt[n+1].display(); printf("/n");<br />return 0;<br />}
題目二:The Primes
很麻煩的一道題目,花了好久才不TLE,不想再寫第二遍了!
/*<br />ID: zhangji42<br />PROG: prime3<br />LANG: C++<br />*/<br />#include <iostream><br />#include <vector><br />#include <algorithm><br />#include <string><br />#include <string.h><br />#include <stdio.h><br />#include <sstream><br />#include <time.h><br />using namespace std;<br />const int maxp = 100000;<br />struct type {<br />int num, n[6];<br />};<br />bool h[maxp] = {0};<br />bool pri[10][10][10][10][10]={0};<br />int len = 0, sum, first;<br />string s[200];<br />int f, mid;<br />type n1, n2, n3, n4, n5, n6;<br />type type1[10][100];//means all the primes and all odd digits<br />type type2[10][100];//not zero<br />type type4[10][100];<br />type type3[10][10][10][100];<br />int main() {<br />freopen("prime3.in", "r" ,stdin);<br />freopen("prime3.out", "w", stdout);<br />void makeprime();<br />void work();<br />int get(int,int);<br />scanf("%d%d", &sum, &first);<br />makeprime();<br />work();<br />sort(s, s+len);<br />for (int i = 0; i < len; i++) {<br />if (i) cout << endl;<br />cout << s[i];<br />}<br />return 0;<br />}<br />int get(int n, int k) {<br />if (k == 1) return n/10000;<br />if (k == 2) return (n/1000) % 10;<br />if (k == 3) return (n/100) % 10;<br />if (k == 4) return (n/10) % 10;<br />if (k == 5) return n % 10;<br />}<br />void makeprime() {<br />for (int i = 2; i < maxp; i++)<br />if (!h[i]) {<br />for (int j = i+i; j < maxp; j += i) h[j] = 1;<br />if (i <= 10000) continue;<br />bool odd = true, zero = false;<br />type tmp;<br />tmp.num = i;<br />int ssum = 0, ii = i;<br />for (int j = 1; j <= 5; j++) {<br />tmp.n[j] = get(i, j);<br />if (tmp.n[j] % 2== 0) odd = false;<br />if (!tmp.n[j]) zero = true;<br />ssum += ii % 10;<br />ii /= 10;<br />}<br />if (ssum != sum) {<br />h[i] = 1;<br />continue;<br />}<br />pri[get(i, 1)][get(i, 2)][get(i, 3)][get(i, 4)][get(i, 5)] = 1;<br />//printf("%d/n", i);<br />if (tmp.n[1] == first) {<br />type4[tmp.n[5]][++type4[tmp.n[5]][0].num] = tmp;<br />if (!zero) type2[tmp.n[5]][++type2[tmp.n[5]][0].num] = tmp;<br />}<br />if (odd) type1[tmp.n[5]][++type1[tmp.n[5]][0].num] = tmp;<br />type3[tmp.n[1]][tmp.n[3]][tmp.n[5]][++type3[tmp.n[1]][tmp.n[3]][tmp.n[5]][0].num] = tmp;<br />}<br />}<br />void work() {<br />int i, j, k, i1, i2, i3, ff, ii, jj;<br />int left1, left2, left3, left4, row2, row3, row4, col2, col3, col4;<br />for (ff = 0; ff < 5; ff++) {<br />f = ff*2+1;<br />for (i = 1; i <= type1[f][0].num; i++)<br />for (j = 1; j <= type1[f][0].num; j++) {<br />n1 = type1[f][i];<br />n2 = type1[f][j];<br />ii = n1.n[1];jj = n2.n[1];<br />for (i2 = 1; i2 <= type4[f][0].num; i2++) {<br />n4 = type4[f][i2];<br />mid = n4.n[3];<br />for (k = 1; k <= type3[ii][mid][jj][0].num; k++) {<br />n6 = type3[ii][mid][jj][k];<br />for (i1 = 1; i1 <= type2[ii][0].num; i1++) {<br />n3 = type2[ii][i1];<br />left1 = sum - n3.n[2] - n4.n[2] - n6.n[4] - n2.n[2];<br />if (left1 < 0 || left1 >= 10) continue;<br />left3 = sum - n3.n[4] - n6.n[2] - n4.n[4] - n2.n[4];<br />if (left3 < 0 || left3 >= 10) continue;<br />if (!pri[n3.n[2]][n4.n[2]][left1][n6.n[4]][n2.n[2]]) continue;//row2<br />if (!pri[n3.n[4]][n6.n[2]][left3][n4.n[4]][n2.n[4]]) continue;//row4<br />for (i3 = 1; i3 <= type2[jj][0].num; i3++) {<br />n5 = type2[jj][i3];<br />left2 = sum - n5.n[2] - n4.n[2] - n6.n[2] - n1.n[2];<br />if (left2 < 0 || left2 >= 10) continue;<br />left4 = sum - n5.n[4] - n6.n[4] - n4.n[4] - n1.n[4];<br />if (left4 < 0 || left4 >= 10) continue;<br />if (!pri[n3.n[3]][left2][n4.n[3]][left4][n2.n[3]]) continue;//row3<br />if (!pri[n5.n[2]][n4.n[2]][left2][n6.n[2]][n1.n[2]]) continue;//col2<br />if (!pri[n5.n[3]][left1][n4.n[3]][left3][n1.n[3]]) continue;//col3<br />if (!pri[n5.n[4]][n6.n[4]][left4][n4.n[4]][n1.n[4]]) continue;//col4<br />/*把方案整個儲存到一個字串中,用了字串檔案流*/<br />ostringstream ss;<br />ss<<n5.num<<'/n'<br /><<n3.n[2]<<n4.n[2]<<left1<<n6.n[4]<<n2.n[2]<<'/n'<br /><<n3.n[3]<<left2<<n4.n[3]<<left4<<n2.n[3]<<'/n'<br /><<n3.n[4]<<n6.n[2]<<left3<<n4.n[4]<<n2.n[4]<<'/n'<br /><<n1.num<<'/n';<br />s[len]=ss.str();<br />len++;<br />}<br />}<br />}<br />}<br />}<br />}<br />}<br />/*<br /> Test 1: TEST OK [0.011 secs, 6040 KB]<br /> Test 2: TEST OK [0.011 secs, 6040 KB]<br /> Test 3: TEST OK [0.022 secs, 6040 KB]<br /> Test 4: TEST OK [0.043 secs, 6040 KB]<br /> Test 5: TEST OK [0.032 secs, 6040 KB]<br /> Test 6: TEST OK [0.076 secs, 6040 KB]<br /> Test 7: TEST OK [0.076 secs, 6040 KB]<br /> Test 8: TEST OK [0.130 secs, 6040 KB]<br /> Test 9: TEST OK [0.108 secs, 6040 KB]<br /> Test 10: TEST OK [0.184 secs, 6040 KB]<br />*/
題目三:Street Race
** Description: 第一問為求有向圖的割,第二問為求無向圖的割
** Algorithm: DFS
** Analysis: 完全圖的3個性質:
1.任意一個點從起點可達;
2.任意一個點可到達終點;
3.終點出度為0;
第一問的答案保證了沒有從分割1到分割2的邊;
第二問的答案同時要保證沒有分割2到分割1的邊;
故第二問可以在第一問的基礎上展開。同時也可以保證分割的兩部分都是完全圖!
但是貌似資料裡面沒有判斷第二問的分割點沒有自環邊。
交上去發現有這種資料,但是按照可以的來算的
/*<br />ID: zhangji42<br />TASK: race3<br />LANG: C++<br />*/<br />#include <stdio.h><br />#include <string.h><br />//#include <vector><br />#include <iostream><br />#define MAXN 60<br />using namespace std;<br />int f[MAXN][MAXN], vis[MAXN];<br />//vector <int> ans1;<br />//vector <int> ans2;<br />int ans1[MAXN]={0}; int s1 = 0;<br />int ans2[MAXN]={0}; int s2 = 0;<br />int i, n;</p><p>bool DFS(int x) {<br />if (x == n) return true;<br />for (int i = 1; i <= n; i++)<br />if (!vis[i] && f[x][i]) {<br />vis[i] = 1;<br />if (DFS(i)) return true;<br />}<br />return false;<br />}<br />bool IsCut(int x) {<br />for (int i = 0; i <= n; i++)<br />if (f[x][i])<br />{<br />if (vis[i] == 1) return true;<br />else<br />if(vis[i] != 2) {<br />vis[i] = 2;<br />if (IsCut(i)) return true;<br />}<br />}<br />return false;<br />}</p><p>int main(){<br />freopen("race3.in", "r", stdin);<br />freopen("race3.out", "w", stdout);</p><p>n = 0;<br />do {<br />int _u;<br />scanf("%d", &_u);<br />if (_u == -1) break;<br />while (_u != -2) {<br />f[n][_u] = 1;<br />//if (n == _u) ans2[n] = -1;<br />scanf("%d", &_u);<br />}<br />n++;<br />} while (1);<br />n--;</p><p>memset(vis,0,sizeof(vis));<br />for (i = 1; i < n; i++)<br />{<br />memset(vis,0,sizeof(vis));<br />vis[0] = 1;<br />vis[i] = 2;<br />if (!DFS(0)) {<br />ans1[i] = 1, s1++;<br />if (ans2[i] >= 0 && !IsCut(i)) ans2[i] = 1, s2++;<br />}<br />}<br />printf("%d", s1);<br />for (i = 1; i <= n ; i++)<br />if (ans1[i]==1) printf(" %d", i);<br />printf("/n%d", s2);<br />for (i = 1; i <= n; i++)<br />if (ans2[i]==1) printf(" %d", i);<br />printf("/n");<br />return 0;<br />}<br />/**********************************************<br />** Description: 第一問為求有向圖的割,第二問為求無向圖的割<br />** Algorithm: DFS<br />** Analysis: 完全圖的3個性質:<br />1.任意一個點從起點可達;<br />2.任意一個點可到達終點;<br />3.終點出度為0;<br /> 第一問的答案保證了沒有從分割1到分割2的邊;<br /> 第二問的答案同時要保證沒有分割2到分割1的邊;<br />故第二問可以在第一問的基礎上展開。同時也可以保證分割的兩部分都是完全圖!<br />但是貌似資料裡面沒有判斷第二問的分割點沒有自環邊。<br />***********************************************/<br />
題目四: Letter Game
** Description: 這道題目關鍵是理解題意:
** 正確的理解應是 在給定的DICT中找出一個或兩個單詞的組合,
滿足各字母出現的次數不多於給定的輸入的字串中各字母的個數
** Analysis: 一開始可能會害怕枚舉,應為感覺資料範圍好大的,但是可以經過初步刪選,得到的只是很小的一部分
兩個的情況只要枚舉一下就可以了
** NOTE: 由於要按照字典序,可以把最後一個設為空白串
#include <algorithm><br />#include <stdio.h><br />#include <string.h><br />#include <iostream><br />#define MAXM 1000<br />using namespace std;<br />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};<br />char s[10], word[MAXM][10];<br />int t[26], pt[26], f[MAXM][MAXM], d[MAXM];<br />int i, j;<br />int check(int i, int j) {<br />memcpy(pt,t,sizeof(t));<br />int p;<br />for (p = 0; word[i][p]; p++)<br />if (--pt[word[i][p]-'a'] < 0) return -1;<br />for (p = 0; word[j][p]; p++)<br />if (--pt[word[j][p]-'a'] < 0) return -1;<br />return d[i]+d[j];<br />}<br />int main(){<br />FILE *fin = fopen("lgame.in", "r");<br />FILE *dict = fopen("lgame.dict", "r");<br />FILE *fout = fopen("lgame.out", "w");<br />fscanf(fin,"%s", s);<br />memset(t,0,sizeof(t));<br />for (i = 0; s[i]; i++)<br />t[s[i]-'a']++;<br />int ans = 0, m = 0, sum = 0;<br />while (fscanf(dict,"%s", s) && s[0] != '.') {<br />memcpy(pt,t,sizeof(t));<br />sum = 0;<br />for (i = 0; s[i]; i++) {<br />if (--pt[s[i]-'a'] < 0) break;<br />sum += v[s[i]-'a'];<br />}<br />if (s[i]) continue;<br />strcpy(word[m], s);<br />d[m++] = sum;<br />}<br />word[m][0] = '/0';<br />d[m++] = 0;<br />for (i = 0; i < m-1; i++)<br />for (j = i+1; j < m; j++) {<br />f[i][j] = check(i, j);<br />if (f[i][j] > ans) ans = f[i][j];<br />}<br />fprintf(fout, "%d/n", ans);<br />for (i = 0; i < m-1; i++)<br />for (j = i+1; j < m; j++)<br />if (f[i][j] == ans)<br />if (j == m-1) fprintf(fout, "%s/n", word[i]); else fprintf(fout, "%s %s/n", word[i], word[j]);<br />return 0;<br />}