UVALive 4126 (ac自动机做状态类)
来源:互联网 发布:用linux可以上百度吗 编辑:程序博客网 时间:2024/04/29 14:58
题意:
给定最多10个长度不超过10的子串,让构造长度为n(n<=25)的字符串使得给定的子串都在该串中出现,问这种串有多少。
分析:
暴力是26^25中可能性,那么怎样精简状态,可以定义d[ i ][ j ][ s ]为当前构造的串长为i且已经到达自动机j位置,已经生成的子串状态为s,接着往下构造所能生成的合法串有多少。
状态转移,就是直接暴力枚举一下下一个字母是谁,在自动机中做状态转移。
一开始用ac自动机做状态不是很好理解,j其实是代表着前面走到i位置,所有最大匹配在自动机中为j的串,那么转移也如此。
#include <cstdio>#include <algorithm>#include <cstring>#include <iostream>#include <queue>#include <set>#include <string>using namespace std;typedef long long ll;#define rep(i,n) for(int i=0;i<(int)n;i++)#define rep1(i,x,y) for(int i=x;i<=y;i++)const int maxnnode = 110;const int sigma_size = 26;struct Trie{ int ch[maxnnode][sigma_size]; int val[maxnnode],f[maxnnode],last[maxnnode]; int cnt; void init(){ cnt = 0; memset(ch[0],0,sizeof(ch[0])); val[0] = 0; memset(val,0,sizeof(val)); } int id(char c){return c-'a';} void insert(char* s,int x){ int n=strlen(s),u=0; rep(i,n){ int c = id(s[i]); if(!ch[u][c]){ ch[u][c]=++cnt; val[cnt]=0; memset(ch[cnt],0,sizeof(ch[cnt])); } u = ch[u][c]; } val[u] = x; } void build(){ f[0] = last[0]=0; queue<int> Q; rep(i,sigma_size){ if(ch[0][i]) Q.push(ch[0][i]),f[ch[0][i]]=last[ch[0][i]]=0; } while(!Q.empty()){ int u=Q.front(); Q.pop(); rep(i,sigma_size){ if(!ch[u][i]){ ch[u][i] = ch[f[u]][i]; continue; } int v = ch[u][i]; f[v] = ch[f[u]][i]; last[v] = (val[f[v]] ? f[v] : last[f[v]]); Q.push(v); } } } int print_(int u){ cnt = 0; while(u) { cnt|=(1<<(val[u]-1)); u = last[u]; } return cnt; }}ac;const int maxn = 26;ll d[maxn][maxnnode][(1<<10)+10];int n,m;ll dp(){ memset(d[n],0,sizeof(d[n])); for(int j=0;j<maxnnode;j++) d[n][j][(1<<m)-1]=1; int te = ac.cnt; for(int i=n-1;i>=0;i--) rep1(j,0,te) for(int s=0;s<(1<<m);s++){ d[i][j][s] = 0; rep(k,sigma_size){ int c = ac.ch[j][k]; int ts = ac.print_(ac.val[c] ? c : ac.last[c]); d[i][j][s]+=d[i+1][c][(s|ts)]; } } return d[0][0][0];}vector<char> aa;void print_(int i,int j,int s){ if(i == n){ rep(i,aa.size()) cout<<aa[i]; cout<<endl; return ; } rep(k,sigma_size){ int c = ac.ch[j][k]; int ts = ac.print_(ac.val[c] ? c : ac.last[c]); if(d[i+1][c][s|ts]) { aa.push_back('a'+k); print_(i+1,c,s|ts); aa.pop_back(); } }}set<string> vvis;int main(){ int kase=1; vvis.clear(); while(scanf("%d %d",&n,&m)==2 && n){ vvis.clear(); ac.init(); int rm = 0; rep(i,m){ char s[30]; scanf("%s",s); string te = s ; if(!vvis.count(te)){ ac.insert(s,++rm); vvis.insert(te); } } m = rm; ac.build(); ll ans = dp(); aa.clear(); printf("Case %d: %lld suspects\n",kase++,ans); if(ans <= 42){ print_(0,0,0); } } return 0;}
0 0
- UVALive 4126 (ac自动机做状态类)
- UVALive-4126 AC自动机
- UVALive 4126 Password Suspects (AC自动机+DP)
- UVALive 4670 (AC自动机)
- UVALive 4670 AC自动机
- UVALive 4670(AC自动机)
- 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 4670 Dominating Patterns(AC自动机)
- UVALive 6495 Probability Paradox AC自动机+高斯消元
- UVALive 4670 - Dominating Patterns (AC自动机)
- UVALive 3490 Generator(AC自动机+dp+高斯消元)
- uvalive 3490 解法二 AC自动机 + 高斯消元
- UVAlive 4670 Dominating Patterns [AC自动机]
- UVALIVE Dominating Patterns (AC自动机)
- UVAlive-4670-Dominating Patterns(AC自动机)
- 虫食算
- ARM定制
- 断言(Assertion)需要注意的一个地方
- shell脚本出错而重复尝试
- Assertion failure in -[UIApplication _runWithMainScene:transitionContext:completion:]解决方法
- UVALive 4126 (ac自动机做状态类)
- 【笔记】最长上升子序列
- spark之4:编程指南
- spark之11:编程指南(v1.2.1翻译)
- a标签的onclick事件与href详解
- 每日好东西传送门---科普
- 【SQL优化】子查询展开
- spark之12:集群模式概述
- 自测-2 素数对猜想 (20分)