挺扯的一个题,解码有点问题+注意用int存,跟HDU2222差不多...
#include <iostream> #include <cstring> #include <cstdio> #include <queue> #include <algorithm> #include <cstdlib> using namespace std; #define N 60010 int trie[N][260]; int que[100000]; int fail[100000]; int hash[1001]; int o[100001]; int str[100000]; int t,num; void CL() { memset(trie,-1,sizeof(trie)); memset(o,0,sizeof(o)); t = 1; } int fun(char x) { if(x >= 'A'&&x <= 'Z') return x-'A'; else if(x >= 'a'&&x <= 'z') return x-'a'+26; else if(x >= '0'&&x <= '9') return x-'0'+52; else if(x == '+') return 62; else return 63; } void judge(char *s) { int i,j,len,temp,n; len = strlen(s); n = 0; for(i = 0; i < len; i ++) { if(s[i] == '=') { n -= 2;//开始这里没理解对。 continue; } temp = fun(s[i]); for(j = 5; j >= 0; j --) { if(temp&(1<<j)) que[n++] = 1; else que[n++] = 0; } } for(i = 0; i < n;) { str[i/8] = 0; for(j = 7; j >= 0; j --) { if(que[i]) str[i/8] += 1<<j; i ++; } } num = n/8; } void insert(int x) { int i,len,root; len = num; root = 0; for(i = 0; i < len; i ++) { if(trie[root][str[i]] == -1) { trie[root][str[i]] = t ++; } root = trie[root][str[i]]; } o[root] = x; } void build_ac() { int head,tail,front,i; head = tail = 0; for(i = 0; i < 260; i ++) { if(trie[0][i] != -1) { fail[trie[0][i]] = 0; que[tail++] = trie[0][i]; } else { trie[0][i] = 0; } } while(head != tail) { front = que[head++]; for(i = 0; i < 260; i ++) { if(trie[front][i] != -1) { que[tail++] = trie[front][i]; fail[trie[front][i]] = trie[fail[front]][i]; } else { trie[front][i] = trie[fail[front]][i]; } } } } void query() { int len,key,temp,i,root; root = 0; len = num; for(i = 0; i < len; i ++) { temp = str[i]; root = trie[root][temp]; key = root; while(key != 0) { hash[o[key]] = 1; key = fail[key]; } } } int main() { int n,i,m,j; char ch[5000]; while(scanf("%d",&n)!=EOF) { CL(); for(i = 1; i <= n; i ++) { scanf("%s",ch); judge(ch); insert(i); } build_ac(); scanf("%d",&m); for(i = 0; i < m; i ++) { memset(hash,0,sizeof(hash)); scanf("%s",ch); judge(ch); query(); int ans = 0; for(j = 1; j <= n; j ++) { if(hash[j]) ans ++; } printf("%d ",ans); } printf(" "); } return 0; }
记录路径有点麻烦,注意答案为0的时候输出空。
#include <cstdio> #include <cstring> #include <iostream> using namespace std; #define N 51000 int trie[N][26]; int fail[N]; int o[N]; int que[N]; int w[101]; int t; char str[101][101]; int dp[101][1001]; int in[101][1001]; void CL() { memset(trie,-1,sizeof(trie)); memset(o,0,sizeof(o)); memset(dp,-1,sizeof(dp)); memset(in,0,sizeof(in)); t = 1; } void insert(char *s,int num) { int i,len,root; root = 0; len = strlen(s); for(i = 0;i < len;i ++) { if(trie[root][s[i]-'a'] == -1) trie[root][s[i]-'a'] = t ++; root = trie[root][s[i]-'a']; } o[root] = num; } void build_ac() { int head,tail,front,i; head = tail = 0; for(i = 0;i < 26;i ++) { if(trie[0][i] != -1) { fail[trie[0][i]] = 0; que[tail++] = trie[0][i]; } else { trie[0][i] = 0; } } while(head != tail) { front = que[head++]; o[front] += o[fail[front]]; for(i = 0;i < 26;i ++) { if(trie[front][i] != -1) { que[tail++] = trie[front][i]; fail[trie[front][i]] = trie[fail[front]][i]; } else { trie[front][i] = trie[fail[front]][i]; } } } } int main() { int cas,n,m,i,j,k; scanf("%d",&cas); while(cas--) { CL(); scanf("%d%d",&n,&m); for(i = 0;i < m;i ++) { scanf("%s",str[i]); } for(i = 0;i < m;i ++) { scanf("%d",&w[i]); } for(i = 0;i < m;i ++) insert(str[i],w[i]); build_ac(); dp[0][0] = 0; for(i = 0;i < n;i ++) { for(j = 0;j < t;j ++) { if(dp[i][j] == -1) continue; for(k = 0;k < 26;k ++) { dp[i+1][trie[j][k]] = max(dp[i][j]+o[trie[j][k]],dp[i+1][trie[j][k]]); } } } int ans = 0,root = 0; for(i = 1;i <= n;i ++) { for(j = 0;j < t;j ++) ans = max(ans,dp[i][j]); } if(ans == 0) { printf(" "); continue; } for(i = 1;i <= n;i ++) { int s = 0; for(j = 0;j < t;j ++) { if(ans == dp[i][j]) { in[i][j] = 1; s = 1; } } if(s) break; } for(i = n-1;i >= 0;i --) { for(j = 0;j < t;j ++) { for(k = 0;k < 26;k ++) { if(in[i+1][trie[j][k]] == 1&&dp[i][j]+o[trie[j][k]] == dp[i+1][trie[j][k]]) in[i][j] = 1; } } } root = 0; for(i = 1;i <= n;i ++) { for(j = 0;j < 26;j ++) { if(in[i][trie[root][j]] && dp[i-1][root] + o[trie[root][j]] == dp[i][trie[root][j]]) { printf("%c",j+'a'); root = trie[root][j]; break; } } if(dp[i][trie[root][j]] == ans) break; } printf(" "); } return 0; }
第一次做,有重复串的。有重复串,直接用指针指向树节点就行了,不能重叠的,标记最后出现的位置就好。
#include <cstdio> #include <cstring> #include <iostream> #include <set> #include <map> #include <vector> #include <cmath> #include <algorithm> using namespace std; #define N 600000 char str[100001]; char ch[100001][6]; int trie[N][26]; int fail[N]; int que[N]; int o[N][2]; int l[N]; int flag[N]; int *ans[100001]; int t; void CL() { memset(flag,-1,sizeof(flag)); memset(trie,-1,sizeof(trie)); memset(o,0,sizeof(o)); t = 1; } void insert(char *s,int num,int type) { int root,len,i; root = 0; len = strlen(s); for(i = 0; i < len; i ++) { if(trie[root][s[i]-'a'] == -1) { trie[root][s[i]-'a'] = t ++; } root = trie[root][s[i]-'a']; } l[root] = len; ans[num] = &o[root][type]; } void build_ac(char *s) { int head,tail,front,i; head = tail = 0; for(i = 0; i < 26; i ++) { if(trie[0][i] != -1) { fail[trie[0][i]] = 0; que[tail++] = trie[0][i]; } else { trie[0][i] = 0; } } while(head != tail) { front = que[head++]; for(i = 0; i < 26; i ++) { if(trie[front][i] != -1) { que[tail++] = trie[front][i]; fail[trie[front][i]] = trie[fail[front]][i]; } else { trie[front][i] = trie[fail[front]][i]; } } } } void query(char *s) { int i,len,root,temp,key; root = 0; len = strlen(s); for(i = 0; i < len; i ++) { temp = s[i] - 'a'; root = trie[root][temp]; key = root; while(key != 0) { if(l[key] > 0) { o[key][0] ++; if(i - flag[key] >= l[key]) { o[key][1] ++; flag[key] = i; } } key = fail[key]; } } } int main() { int i,n,cas = 1,temp; while(scanf("%s",str)!=EOF) { CL(); scanf("%d",&n); for(i = 1; i <= n; i ++) { scanf("%d%s",&temp,ch[i]); insert(ch[i],i,temp); } build_ac(str); query(str); printf("Case %d ",cas++); for(i = 1; i <= n; i ++) printf("%d ",*ans[i]); printf(" "); } return 0; }
很非主流的一个题目,我wa了好几页,竟然是没调用build_ac函数,我在宿舍,姿势不大好,一定是这样....这题直接在Trie树上乱搞就好,这个最短路,很特别,两点之间肯定是线段最短,没有必要DP的。
#include <cstdio> #include <cstring> #include <iostream> #include <map> #include <algorithm> #include <vector> #include <cmath> #include <algorithm> #include <string> using namespace std; double minz; double x[101],y[101]; int trie[1001][51]; int len[101]; int s[101][101]; int fail[1001]; int que[1001]; int o[1001]; int t,n; void CL() { memset(trie,-1,sizeof(trie)); memset(o,0,sizeof(o)); t = 1; } void insert(int x) { int i,root; scanf("%d",&len[x]); root = 0; for(i = 0;i < len[x];i ++) { scanf("%d",&s[x][i]); if(trie[root][s[x][i]] == -1) trie[root][s[x][i]] = t ++; root = trie[root][s[x][i]]; } o[root] = 1; } void build_ac() { int head,tail,i,front; head = tail = 0; for(i = 1;i <= n;i ++) { if(trie[0][i] != -1) { fail[trie[0][i]] = 0; que[tail++] = trie[0][i]; } else { trie[0][i] = 0; } } while(head != tail) { front = que[head++]; if(o[fail[front]]) o[front] = 1; for(i = 1;i <= n;i ++) { if(trie[front][i] != -1) { que[tail++] = trie[front][i]; fail[trie[front][i]] = trie[fail[front]][i]; } else { trie[front][i] = trie[fail[front]][i]; } } } } double dis(int a,int b) { return sqrt((x[a]-x[b])*1.0*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b])); } void dfs(int root,double ans,int ve) { int i; if(ans >= minz) return ; if(o[trie[root][n]] == 0) { minz = min(minz,ans+dis(ve,n)); return ; } for(i = ve+1;i <= n;i ++) { if(o[trie[root][i]]) continue; dfs(trie[root][i],ans+dis(ve,i),i); } } int main() { int m,i; while(scanf("%d%d",&n,&m)!=EOF) { if(n == 0&&m == 0) break; CL(); for(i = 1;i <= n;i ++) scanf("%lf%lf",&x[i],&y[i]); for(i = 1;i <= m;i ++) { insert(i); } build_ac(); minz = 1000000000.0 * 100000000.0; dfs(trie[0][1],0,1); if(minz == 1000000000.0 * 100000000.0) printf("Can not be reached! "); else printf("%.2lf ",minz); } return 0; }
我用java过的。。。一个套路的DP+AC自动机,注意有重复串,用java调试的我很纠结。。。eclipse的单步,太难用了。。。单步还是太慢了。。。对java也是各种不熟。
import java.math.BigInteger; import java.util.Scanner; public class Main { static int t; static int trie[][] = new int[1001][4]; static int o[] = new int[1001]; static int que[] = new int[1001]; static int fail[] = new int[1001]; public static int judge(char s) { if (s == 'A') return 0; else if (s == 'C') return 1; else if (s == 'G') return 2; else if (s == 'T') return 3; return 0; } public static void CL() { int i, j; t = 1; for (i = 0; i <= 1000; i++) { o[i] = 0; for (j = 0; j < 4; j++) trie[i][j] = -1; } } public static void insert(char s[], int len) { // 必须把len传过来 int root, i; root = 0; for (i = 0; i < len; i++) { if (trie[root][judge(s[i])] == -1) trie[root][judge(s[i])] = t++; root = trie[root][judge(s[i])]; } o[root] ++; } public static void build_ac() { int i, head, tail, front; head = tail = 0; for (i = 0; i < 4; i++) { if (trie[0][i] != -1) { que[tail++] = trie[0][i]; fail[trie[0][i]] = 0; } else { trie[0][i] = 0; } } while (head != tail) { front = que[head++]; o[front] += o[fail[front]]; for (i = 0; i < 4; i++) { if (trie[front][i] != -1) { que[tail++] = trie[front][i]; fail[trie[front][i]] = trie[fail[front]][i]; } else { trie[front][i] = trie[fail[front]][i]; } } } } public static void main(String args[]) { Scanner cin = new Scanner(System.in); int n, i, j, k, u, v, w, x, a, b, c, d, temp, cas = 1; String str[] = new String[51]; char ch[] = new char[101]; String s; while (cin.hasNext()) { a = b = c = d = 0; n = cin.nextInt(); if (n == 0) break; cin.nextLine(); CL(); for (i = 0; i < n; i++) { str[i] = cin.nextLine(); ch = str[i].toCharArray(); insert(ch, str[i].length()); } s = cin.nextLine(); ch = s.toCharArray(); for (i = 0; i < s.length(); i++) { temp = judge(ch[i]); if (temp == 0) a++; else if (temp == 1) b++; else if (temp == 2) c++; else d++; } build_ac(); int dp[][][][][] = new int[a + 1][b + 1][c + 1][d + 1][t + 1]; for (i = 0; i <= a; i++) { for (j = 0; j <= b; j++) { for (k = 0; k <= c; k++) { for (u = 0; u <= d; u++) { for (v = 0; v <= t; v++) dp[i][j][k][u][v] = -1; } } } } dp[0][0][0][0][0] = 0; for (i = 0; i < a + b + c + d; i++) { for (j = 0; j <= a; j++) { for (k = 0; k <= b; k++) { for (u = 0; u <= c; u++) { for (v = 0; v <= d; v++) { if (j + k + u + v != i) continue; for (w = 0; w < t; w++) { if (dp[j][k][u][v][w] == -1) continue; for (x = 0; x < 4; x++) { if (x == 0 && j + 1 <= a) { if (dp[j + 1][k][u][v][trie[w][x]] < dp[j][k][u][v][w] + o[trie[w][x]]) dp[j + 1][k][u][v][trie[w][x]] = dp[j][k][u][v][w] + o[trie[w][x]]; } else if (x == 1 && k + 1 <= b) { if (dp[j][k + 1][u][v][trie[w][x]] < dp[j][k][u][v][w] + o[trie[w][x]]) dp[j][k + 1][u][v][trie[w][x]] = dp[j][k][u][v][w] + o[trie[w][x]]; } else if (x == 2 && u + 1 <= c) { if (dp[j][k][u + 1][v][trie[w][x]] < dp[j][k][u][v][w] + o[trie[w][x]]) dp[j][k][u + 1][v][trie[w][x]] = dp[j][k][u][v][w] + o[trie[w][x]]; } else if (x == 3 && v + 1 <= d) { if (dp[j][k][u][v + 1][trie[w][x]] < dp[j][k][u][v][w] + o[trie[w][x]]) dp[j][k][u][v + 1][trie[w][x]] = dp[j][k][u][v][w] + o[trie[w][x]]; } } } } } } } } int ans = 0; for (i = 0; i < t; i++) { if (ans < dp[a][b][c][d][i]) ans = dp[a][b][c][d][i]; } System.out.println("Case " + cas + ": " + ans); cas++; } } }
HDU 3247 Resource Archiver
只有最后一个状态有关。
#include <iostream> #include <cstdio> #include <string> #include <map> #include <algorithm> #include <cstring> #include <queue> using namespace std; #define N 60001 #define INF 0x3f3f3f3f char str[10001]; int trie[60001][2]; int fail[60001]; int flag[60001]; int o[60001]; int in[60001]; int que[60001]; int dis[60001]; int t,n; int dp[1024][11]; int end[11]; int mp[11][11]; void CL() { memset(o,0,sizeof(o)); memset(flag,0,sizeof(flag)); memset(trie,-1,sizeof(trie)); memset(dp,0,sizeof(dp)); t = 1; } void insert(char *s,int x) { int root,len,i; len = strlen(s); root = 0; for(i = 0; i < len; i ++) { if(trie[root][s[i]-'0'] == -1) trie[root][s[i]-'0'] = t ++; root = trie[root][s[i]-'0']; } if(x == -1) { o[root] = 1; } else { flag[root] |= 1<<x; end[x+1] = root; } } void build_ac() { int head,tail,i,front; head = tail = 0; for(i = 0; i < 2; i ++) { if(trie[0][i] != -1) { que[tail++] = trie[0][i]; fail[trie[0][i]] = 0; } else { trie[0][i] = 0; } } while(head != tail) { front = que[head++]; o[front] |= o[fail[front]]; flag[front] |= flag[fail[front]]; for(i = 0; i < 2; i ++) { if(trie[front][i] != -1) { que[tail++] = trie[front][i]; fail[trie[front][i]] = trie[fail[front]][i]; } else { trie[front][i] = trie[fail[front]][i]; } } } } void spfa(int x) { int i,u; for(i = 0; i < t; i ++) { dis[i] = INF; in[i] = 0; } dis[end[x]] = 0; queue<int> que; que.push(end[x]); while(!que.empty()) { u = que.front(); in[u] = 0; que.pop(); for(i = 0; i < 2; i ++) { if(o[trie[u][i]]) continue; if(dis[trie[u][i]] > dis[u] + 1) { dis[trie[u][i]] = dis[u] + 1; if(in[trie[u][i]] == 0) { in[trie[u][i]] = 1; que.push(trie[u][i]); } } } } for(i = 0; i < n; i ++) mp[x][i] = dis[end[i]]; } int main() { int m,i,j,k; while(scanf("%d%d",&n,&m)!=EOF) { if(n == 0&&m == 0) break; CL(); for(i = 0; i < n; i ++) { scanf("%s",str); insert(str,i); } for(i = 0; i < m; i ++) { scanf("%s",str); insert(str,-1); } build_ac(); n ++; for(i = 0; i < n; i ++) { spfa(i); } memset(dp,127,sizeof(dp)); dp[0][0] = 0; for(i = 0; i < 1<<(n-1); i ++) { for(j = 0; j < n; j ++) { for(k = 0; k < n; k ++) { if(mp[j][k] == INF) continue; dp[i|flag[end[k]]][k] = min(dp[i|flag[end[k]]][k],dp[i][j]+mp[j][k]); } } } int ans = INF; for(i = 0; i < n; i ++) { ans = min(dp[(1<<(n-1))-1][i],ans); } printf("%d ",ans); } return 0; }
ZOJ 3494 BCD Code
数位DP+AC自动机,写错好几个地方,然后...各种wa很棒的一题...
#include <iostream> #include <cstdio> #include <string> #include <map> #include <algorithm> #include <cstring> #include <queue> using namespace std; #define MOD 1000000009 #define LL long long int flag[11][4]; int num[301]; int trie[5001][2]; int fail[5001]; int o[5001]; int que[5001]; int dp[201][5001]; int t,slen; void CL() { memset(o,0,sizeof(o)); memset(trie,-1,sizeof(trie)); t = 1; } void insert(char *s) { int root,len,i; len = strlen(s); root = 0; for(i = 0; i < len; i ++) { if(trie[root][s[i]-'0'] == -1) trie[root][s[i]-'0'] = t ++; root = trie[root][s[i]-'0']; } o[root] = 1; } void build_ac() { int head,tail,i,front; head = tail = 0; for(i = 0; i < 2; i ++) { if(trie[0][i] != -1) { que[tail++] = trie[0][i]; fail[trie[0][i]] = 0; } else { trie[0][i] = 0; } } while(head != tail) { front = que[head++]; o[front] |= o[fail[front]]; for(i = 0; i < 2; i ++) { if(trie[front][i] != -1) { que[tail++] = trie[front][i]; fail[trie[front][i]] = trie[fail[front]][i]; } else { trie[front][i] = trie[fail[front]][i]; } } } } void fun(char *s) { int i,len; len = strlen(s); s[len-1] --; for(i = len-1;i >= 0;i --) { if(s[i] < '0') { s[i] += 10; s[i-1] --; } } } LL dfs(int pos,int pre,int pix,int bound) { LL ans = 0; int i,j,end,z,root; if(pos == slen) return 1; if(!pix&&!bound&&dp[pos][pre] != -1) return dp[pos][pre]; end = bound ? num[pos]:9; for(i = 0;i <= end;i ++) { z = 0; root = pre; for(j = 0;j < 4;j ++) { root = trie[root][flag[i][j]]; if(o[root]) z = 1; } if(pix&&i == 0&&pos != slen-1) { ans += dfs(pos+1,0,1,(i == end)&&bound); ans %= MOD; continue; } if(z) continue; ans += dfs(pos+1,root,0,(i == end)&&bound); ans %= MOD; } if(!bound) dp[pos][pre] = ans; return ans%MOD; } LL judge(char *s) { int len = strlen(s),i; memset(dp,-1,sizeof(dp)); slen = len; for(i = len-1;i >= 0;i --) num[i] = s[i] - '0'; return dfs(0,0,1,1); } int main() { int t,i,j,n; char str[201]; char x[201],y[201]; for(i = 0;i < 10;i ++) { for(j = 0;j < 4;j ++) { if(i&(1<<j)) flag[i][3-j] = 1; else flag[i][3-j] = 0; } } scanf("%d",&t); while(t--) { CL(); scanf("%d",&n); for(i = 0;i < n;i ++) { scanf("%s",str); insert(str); } build_ac(); scanf("%s%s",x,y); fun(x); LL ans = (judge(y) - judge(x))%MOD; if(ans < 0) ans += MOD; printf("%lld ",ans); } return 0; }