uva1076 - Password Suspects

    xiaoxiao2022-07-07  168

    链接

    https://cn.vjudge.net/problem/UVA-1076

    题解

    这是一道world final题 方案数就直接AC自动机上状压dp, f i j k f_{ijk} fijk表示长度为 i i i,当前走到了第 j j j个结点,每个串有没有包含为 k k k(二进制状压)的方案数 输出方案比较蛋疼,我是记录了每个方案是由哪个方案转移过来的,最后一遍 d f s dfs dfs,各种 s t l stl stl瞎搞就出来了(说起来容易,做起来还是很考验代码能力的)

    联想

    其实吧,所谓 A C AC AC自动机上的状压 d p dp dp,听起来很长,好像挺 6 6 6一样,但其实 A C AC AC自动机只是提供了一个偏序关系(把串的长度考虑进去),定义了一种转移顺序,去掉 A C AC AC自动机的话,这题就只是个状压 d p dp dp入门级题目 还有一种题目是算期望或者算概率的,那种题的串可能会达到无限长,但是 A C AC AC自动机在其中起的作用还是定义“如何转移”,最后用一个高斯消元算一算就完了。 所以说其实 A C AC AC自动机只是一种工具,说到底这些"AC自动机上的xxx"题目,就还是一些普通算法题套到数据结构上去罢了。

    代码

    #include <bits/stdc++.h> #define maxn 110 #define cl(x) memset(x,0,sizeof(x)) using namespace std; typedef long long ll; ll f[30][maxn][2019]; vector<int> num[maxn]; vector< vector<int> > g[30][maxn][2019]; struct ACautomaton { int trie[maxn][30], tot, fail[maxn], tail[maxn]; void init() //clear the arrays { memset(trie,0,sizeof(trie)); memset(fail,0,sizeof(fail)); memset(tail,0,sizeof(tail)); tot=1; } int insert(int *r, int len) //insert a string into trie tree { auto pos=1; for(auto i=1;i<=len;i++) pos = trie[pos][r[i]] ? trie[pos][r[i]] : trie[pos][r[i]]=++tot; tail[pos]++; return pos; } void build() //build the aca { queue<int> q; int u, v, f; q.push(1); while(!q.empty()) { u=q.front(); q.pop(); for(auto i=1;i<=26;i++) if(trie[u][i]) { v=trie[u][i]; for(f=fail[u];f and !trie[f][i];f=fail[f]); fail[v] = f ? trie[f][i] : 1; tail[v]+=tail[fail[v]]; q.push(v); } } } int move(int pos, int c) { for(;pos and !trie[pos][c];pos=fail[pos]); return pos ? trie[pos][c] : 1; } }aca; void dfs(int i, int j, int k, vector<string>& lis, string now) { if(i==0) { lis.emplace_back(now); return; } for(auto v:g[i][j][k]) { char t[2]; t[0]=char(v[2]+'a'-1); t[1]='\0'; dfs(i-1,v[0],v[1],lis,string(t)+now); } } int main() { int n, m, i, j, k, alpha, kase(0), r[maxn]; char s[maxn]; while(scanf("%d%d",&n,&m), (n or m)) { aca.init(); for(i=0;i<maxn;i++)num[i].clear(); for(i=1;i<=m;i++) { scanf("%s",s+1); auto len=strlen(s+1); for(auto i=1;i<=len;i++)r[i]=s[i]-'a'+1; auto pos = aca.insert(r,len); num[pos].emplace_back(i); } aca.build(); cl(f); f[0][1][0]=1; for(i=0;i<=n;i++)for(j=1;j<=aca.tot;j++)for(k=0;k<(1<<m);k++)g[i][j][k].clear(); for(i=0;i<n;i++) { for(j=1;j<=aca.tot;j++) { for(k=0;k<(1<<m);k++) { if(f[i][j][k]==0)continue; for(alpha=1;alpha<=26;alpha++) { auto to = aca.move(j,alpha), sta(k); for(auto pos=to;pos>1;pos=aca.fail[pos]) { for(auto x : num[pos])sta |= 1<<(x-1); } f[i+1][to][sta] += f[i][j][k]; if(f[i][j][k]<=42)g[i+1][to][sta].emplace_back( vector<int>{j,k,alpha} ); } } } } ll ans(0ll); for(i=1;i<=aca.tot;i++) { ans += f[n][i][(1<<m)-1]; } printf("Case %d: %lld suspects\n",++kase,ans); if(ans<=42) { vector<string> lis; for(i=1;i<=aca.tot;i++) dfs(n,i,(1<<m)-1,lis,""); sort(lis.begin(),lis.end()); for(auto s:lis)cout<<s<<endl; } } return 0; }
    最新回复(0)