HDU 2825
下午连续看了两题的AC自动机+DP题,发现都有点规律了,都是由trie图循环赋值,按照结点一步步向外推的,而且状态设的也很相似。。。
dp[i][j][k],一开始以为至少k个是可以相同的,其实这k个串应该是不同的,于是就可以按照二进制压缩这M个串,1表示选上了这个串。注意一下fail指向的结点要与当前自身的选串的状态或上就可以了。为当前处于i状态,前j个字符。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <climits> #include <string.h> #include <queue> #include <cmath> #include <map> #include <vector> #define LL __int64 using namespace std; const int dictsize=26; const int MOD =20090717; const int Maxn=150; const int root=0; const int state=(1<<10)-1; int head,tail; int que[Maxn]; struct Node { int fail,next[dictsize]; int tag; void initial(){ fail=-1,tag=false; for(int i=0;i<dictsize;i++) next[i]=-1; } }trie[Maxn]; int tot,n,m,l; char str[15]; int dp[Maxn][26][state+1]; void Insert_trie(int s){ int p=0,i=0; while(str[i]){ if(trie[p].next[str[i]-'a']==-1) trie[p].next[str[i]-'a']=++tot; p=trie[p].next[str[i]-'a']; i++; } trie[p].tag=(1<<s); } void build_ac(){ que[tail++]=root; int i,tmp,p; while(head!=tail){ tmp=que[head++]; p=-1; for(int i=0;i<dictsize;i++){ if(trie[tmp].next[i]!=-1){ if(tmp==root) trie[trie[tmp].next[i]].fail=root; else{ p=trie[tmp].fail; while(p!=-1){ if(trie[p].next[i]!=-1){ trie[trie[tmp].next[i]].fail=trie[p].next[i]; break; } p=trie[p].fail; } if(p==-1){ trie[trie[tmp].next[i]].fail=root; } } trie[trie[tmp].next[i]].tag|=trie[trie[trie[tmp].next[i]].fail].tag; que[tail++]=trie[tmp].next[i]; } else{ //trie[tmp].next[i]==-1 if(tmp==root) trie[tmp].next[i]=root; else{ p=trie[tmp].fail; while(p!=-1){ if(trie[p].next[i]!=-1){ trie[tmp].next[i]=trie[p].next[i]; break; } p=trie[p].fail; } if(p==-1){ trie[tmp].next[i]=root; } } } } } } bool ok(int s,int k){ int c=0; while(s){ if(s&1) c++; s>>=1; } if(c>=k) return true; return false; } int main(){ while(scanf("%d%d%d",&n,&m,&l)&&n||m||l){ tot=head=tail=0; for(int i=0;i<110;i++) trie[i].initial(); for(int i=0;i<m;i++){ scanf("%s",str); Insert_trie(i); } build_ac(); memset(dp,0,sizeof(dp)); dp[0][0][0]=1; int alstate=(1<<m)-1,son; for(int j=0;j<=n;j++){ for(int i=0;i<=tot;i++){ for(int k=0;k<=alstate;k++){ if(dp[i][j][k]>0){ for(int e=0;e<dictsize;e++){ son=trie[i].next[e]; dp[son][j+1][trie[son].tag|k]=(dp[son][j+1][trie[son].tag|k]+dp[i][j][k])%MOD; } } } } } int ans=0; for(int i=0;i<=tot;i++){ for(int k=0;k<=alstate;k++){ if(ok(k,l)){ ans=(ans+dp[i][n][k])%MOD; } } } printf("%d\n",ans); } return 0; }