UVALive 4126 Password Suspects (AC自动机+DP)
来源:互联网 发布:淘宝子账号被限制登录 编辑:程序博客网 时间:2024/05/16 09:47
题目链接:https://vjudge.net/problem/UVALive-4126
题目大意:有一个长度为n的未知小写字母串,你已经知道了它的一些连续子串(但不知道出现位置,这些字串可能相互重叠)。比如,若长度为10,有两个连续子串hello和world,则只有两种可能:helloworld和worldhello。求可能的串的个数,若个数不超过42,按字典序输出所有串。
思路:将连续子串构造AC自动机。然后在自动机上进行DP,令dp(u, step, S)表示当前在结点u,已经走了step步(即已经造出了长度为step的串),包含的连续子串集合为S,接着往下构造的方案数,答案即为dp(0, 0, 0)。 输出方案时同样按照DP方程的思路进行转移即可。
#include<cstdio>#include<cstring>#include<string>#include<cctype>#include<iostream>#include<set>#include<map>#include<cmath>#include<sstream>#include<vector>#include<stack>#include<queue>#include<algorithm>#define fin freopen("a.txt","r",stdin)#define fout freopen("a.txt","w",stdout)typedef long long LL;typedef unsigned long long ULL;using namespace std;const int inf = 1e9 + 10;const int maxnode = 105;const int sigma_size = 26;const int maxn = 5e4 + 10;int Max;char s[100];LL dp[maxnode][maxnode][1<<10];int n, m;struct Tree{int ch[maxnode][sigma_size];int f[maxnode];int val[maxnode];int last[maxnode];int sz;int idx(char c) { return c - 'a'; } void init() { memset(ch[0], 0, sizeof ch[0]); sz = 1; } void getFail() { queue<int> q; f[0] = 0; for(int c = 0; c < sigma_size; c++) { int u = ch[0][c]; if(u) { f[u] = 0; q.push(u); last[u] = 0;} } while(!q.empty()) { int r = q.front(); q.pop(); for(int c = 0; c < sigma_size; c++) { int u = ch[r][c]; if(!u) { ch[r][c] = ch[f[r]][c]; continue; } q.push(u); int v = f[r]; while(v && !ch[v][c]) v = f[v]; f[u] = ch[v][c]; last[u] = val[f[u]] ? f[u] : last[f[u]]; } } } bool insert(char *s, int v) { bool ok = false; int n = strlen(s), u = 0; for(int i = 0; i < n; i++) { int c = idx(s[i]); if(!ch[u][c]) { memset(ch[sz], 0, sizeof ch[sz]); val[sz] = 0; ch[u][c] = sz++; ok = true; } u = ch[u][c]; } if(ok) val[u] = v; return ok; } void print(int u, int& S) { if(u) { S |= (1<<(val[u]-1)); print(last[u], S); } } LL DP(int u, int step, int S) { if(step == n) { return S == (1<<m)-1; } LL &ans = dp[u][step][S]; if(ans >= 0) return ans; ans = 0; for(int i = 0; i < sigma_size; i++) { int v = ch[u][i]; int S2 = S; if(val[v]) print(v, S2); else if(last[v]) print(last[v], S2); ans += DP(v, step+1, S2); } return ans; } void Out(int u, int step, int S, string s) { if(step == n) { printf("%s\n", s.c_str()); return ;} for(int i = 0; i < sigma_size; i++) { int v = ch[u][i]; int S2 = S; if(val[v]) print(v, S2); else if(last[v]) print(last[v], S2); if(DP(v, step+1, S2)) Out(v, step+1, S2, s + char('a'+i)); } }}ac;int main() { int kase = 0; while(scanf("%d%d", &n, &m) && n) { ac.init(); memset(dp, -1, sizeof dp); for(int i = 1; i <= m; i++) { scanf("%s", s); if(!ac.insert(s, i)) { m--; i--; } } ac.getFail(); LL ans = ac.DP(0, 0, 0); printf("Case %d: %lld suspects\n", ++kase, ans); if(ans <= 42) { ac.Out(0, 0, 0, ""); } } return 0;}
阅读全文
0 0
- UVALive 4126 Password Suspects (AC自动机+DP)
- UVALive 4126 Password Suspects(AC自动机 + DP)
- UVaLive 4126 - Password Suspects (AC自动机 DP)
- UVALive 4126 Password Suspects(AC自动机+dp)
- UVALive 4126 Password Suspects(AC自动机 套 DP)
- UVALive 4126 (LA 4126) Password Suspects AC自动机 + DP + 剪枝dfs
- UVA 1078 Password Suspects(AC自动机+dp)
- UVA 1076 - Password Suspects(AC自动机+DP)
- uva1076 - Password Suspects AC自动机+状态压缩DP
- UVALive-4126 AC自动机
- uva 1076 - Password Suspects(AC自动机+记忆化搜索)
- UVALive 3490 Generator(AC自动机+dp+高斯消元)
- HDU_2825 Wireless Password AC自动机+dp
- hdu 2825 Wireless Password 【ac自动机+dp】
- HDU 2825 Wireless Password【AC自动机+DP】
- hdu2825 Wireless Password AC自动机+状压DP
- hdu 2825 Wireless Password(ac自动机&dp)
- 【HDU】2825 Wireless Password AC自动机+DP
- Shell
- scanf的安全输入问题
- CvvImage类在MFC中使用的说明
- HDOJ1712 分组背包问题
- BZOJ 4551 树 dfs序+线段树 / 并查集
- UVALive 4126 Password Suspects (AC自动机+DP)
- OCCI调用带有返回结果集的存储过程,获取结果集中指定列的值
- String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getS
- 2017年年度总结
- Android防止按钮过快点击造成多次事件的解决方法
- Redis启动多端口、运行多实例
- java 导出excel实战
- codis3 搭建部署实验
- Ubuntu16.04 安装Pycharm