洛谷P4608 [FJOI2016]所有公共子序列问题 【序列自动机 + dp + 高精】
2018-06-18 22:00
429 查看
题目链接
题解
建个序列自动机后
第一问暴搜
第二问dp + 高精
设\(f[i][j]\)为两个序列自动机分别走到\(i\)和\(j\)节点的方案数,答案就是\(f[0][0]\)
由于空间卡的很紧,高精不仅要压位,还要动态开内存
由于有些状态是没用的,记忆化搜索以减少内存损失
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<map> #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt) #define REP(i,n) for (int i = 1; i <= (n); i++) #define mp(a,b) make_pair<int,int>(a,b) #define cls(s) memset(s,0,sizeof(s)) #define cp pair<int,int> #define LL long long int using namespace std; const int maxn = 3015,P = 1000000000,maxm = 100005,INF = 1000000000; inline int read(){ int out = 0,flag = 1; char c = getchar(); while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();} while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();} return out * flag; } char X[maxn],Y[maxn]; int typ,n,m,last[60]; inline int id(char c){return c >= 'a' ? 26 + c - 'a' : c - 'A';} struct LAM{ int ch[maxn][52],cnt; void build(char* S,int len){ for (int i = 0; i < 52; i++) last[i] = 0; cnt = len; for (int i = len; i; i--){ for (int j = 0; j < 52; j++) ch[i][j] = last[j]; last[id(S[i])] = i; } for (int i = 0; i < 52; i++) ch[0][i] = last[i]; } }A,B; char s[maxn]; int len,ans; void dfs(int u,int v){ ans++; for (int i = 1; i <= len; i++) putchar(s[i]); puts(""); for (int i = 0; i < 52; i++) if (A.ch[u][i] && B.ch[v][i]){ s[++len] = i > 25 ? 'a' + i - 26 : 'A' + i; dfs(A.ch[u][i],B.ch[v][i]); len--; } } void work1(){ dfs(0,0); printf("%d\n",ans); }; struct NUM{ int len; LL* s; void init(){ s = new LL[20]; for (int i = 0; i < 20; i++) s[i] = 0; len = 0; } void out(){ if (!len){puts("0"); return;} printf("%lld",s[len - 1]); for (int i = len - 2; ~i; i--) printf("%09lld",s[i]); } void add(const NUM& a){ LL carry = 0,tmp,L = max(len,a.len); for (int i = 0; i < L; i++){ tmp = s[i] + a.s[i] + carry; s[i] = tmp % P; carry = tmp / P; } if (carry) s[L] += carry; len = 0; for (int i = 19; ~i; i--) if (s[i]){len = i + 1; break;} } }f[maxn][maxn]; int vis[maxn][maxn]; void DFS(int u,int v){ if (vis[u][v]) return; vis[u][v] = true; f[u][v].init(); f[u][v].s[0] = f[u][v].len = 1; for (int i = 0; i < 52; i++) if (A.ch[u][i] && B.ch[v][i]){ DFS(A.ch[u][i],B.ch[v][i]); f[u][v].add(f[A.ch[u][i]][B.ch[v][i]]); } } void work2(){ DFS(0,0); f[0][0].out(); } int main(){ n = read(); m = read(); scanf("%s%s%d",X + 1,Y + 1,&typ); A.build(X,n); B.build(Y,m); if (typ) work1(); else work2(); return 0; }
相关文章推荐
- 【FJOI2016】所有公共子序列问题
- [刷题#1][FJOI2015]所有公共子序列问题
- 最长公共子序列问题-求所有公共子序列(java核心代码实现)
- 一个看似简单却复杂的问题:求两个字符串的 左向右匹配 所有的 最长连续的 公共子字符串( 在每个字符串中先后次序相同的) 序列
- “最长公共字符串子序列”问题的动态规划法算法
- 洛谷 2822 [NOIP2016] 组合数问题 递推
- 公共子序列与公共字串问题
- 所有可能的出栈序列问题及卡塔兰数的应用
- 求所有最大公共子序列的算法实现
- SPOJ1811最长公共子串问题(后缀自动机)
- LCS最大公共子序列问题
- “最长公共字符串子序列”问题的动态规划法算法
- 洛谷P2766最长不下降子序列问题(网络流24题)
- java 动态规划最大公共子序列问题
- 【LOJ】#2172. 「FJOI2016」所有公共子序列问题
- 滚动数组处理数据很大的公共子序列问题
- 求最长公共序列问题
- 洛谷 P2822 [NOIP2016 D2T1] 组合数问题 [90分伪题解]
- 最长公共子串(子序列)、最长递增子序列、最长回文子串等问题
- 最大连续子序列和,乘积,最长递增子串,最长公共子串,子序列等问题(动态规划等)