P4052 [JSOI2007]文本生成器
阿新 • • 發佈:2018-09-10
logs string main ref 傳送門 span 方案 get oid
P4052 [JSOI2007]文本生成器
AC自動機+dp
優秀題解傳送門
設f[ i ][ j ]表示串的長度為 i ,當前在 j 點時不可識別的串的方案數
最後用總方案數減去不可識別方案數就是答案了
因為題解寫的很好所以我就只在代碼中加點註釋了(逃
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int mod=10007; struct data{ int nxt[26],fail,end; }a[6002]; int n,m,cnt,ans=1,f[102][6002]; char q[102]; inline void Trie_build(){ scanf("%s",q); int u=0,len=strlen(q); for(int i=0;i<len;++i){ int p=q[i]-‘A‘; if(!a[u].nxt[p]) a[u].nxt[p]=++cnt; u=a[u].nxt[p]; }++a[u].end; } inline void AC_build(){ queue <int> h;for(int i=0;i<26;++i) if(a[0].nxt[i]) h.push(a[0].nxt[i]); while(!h.empty()){ int x=h.front(); h.pop(); for(int i=0;i<26;++i){ int &to=a[x].nxt[i]; if(to){ a[to].fail=a[a[x].fail].nxt[i]; a[to].end|=a[a[to].fail].end; //如果該串的後綴是可識別的那麽這個串也一定是可識別的 h.push(to); }else to=a[a[x].fail].nxt[i]; } } } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) Trie_build(); AC_build(); f[0][0]=1; for(int i=1;i<=m;++i) for(int j=0;j<=cnt;++j) for(int k=0;k<26;++k) if(!a[a[j].nxt[k]].end) //不可識別 f[i][a[j].nxt[k]]=(f[i][a[j].nxt[k]]+f[i-1][j])%mod; for(int i=1;i<=m;++i) ans=ans*26%mod; for(int i=0;i<=cnt;++i) ans=(ans-f[m][i]+mod)%mod; //總方案數-不可識別方案數 printf("%d",ans); return 0; }
P4052 [JSOI2007]文本生成器