標籤:
bzoj1030[JSOI2007]文本產生器
題意:
給出一個字典和一個長度,要求有多少個這個長度的字串裡含有子串為字典裡的單詞。字串和字典裡的字元都為大寫字母。單詞數≤60,字串及單詞長度≤100。
題解:
在AC自動機上跑dp,求不含字典單詞的個數,再用總個數減。f[i][j]表示當前處理第i個位置,在trie上的節點為j。f[i][j]=sum{f[i+1][ch[x][k]]},x為j的fail祖先,為k為大寫字母,不能走到val為1的節點。注意val的處理,特別是getfail中的“if(val[ch[y][i]])val[ch[x][i]]=1;”一句。
代碼:
1 #include <cstring> 2 #include <cstdio> 3 #include <algorithm> 4 #include <queue> 5 #define maxn 10000 6 #define inc(i,j,k) for(int i=j;i<=k;i++) 7 #define mod 10007 8 using namespace std; 9 10 int n,m,sz,ch[maxn][26],fail[maxn],ans,f[150][maxn]; bool val[maxn];11 void insert(char *s){12 int x=0,len=strlen(s+1); inc(i,1,len){if(!ch[x][s[i]-‘A‘])ch[x][s[i]-‘A‘]=++sz; x=ch[x][s[i]-‘A‘];}13 val[x]=1;14 }15 queue <int> q;16 void getfail(){17 inc(i,0,25)if(ch[0][i])q.push(ch[0][i]),fail[ch[0][i]]=0;18 while(!q.empty()){19 int x=q.front(); q.pop();20 inc(i,0,25)if(ch[x][i]){21 int y=fail[x]; while(y&&!ch[y][i])y=fail[y]; if(ch[y][i])fail[ch[x][i]]=ch[y][i];22 if(val[ch[y][i]])val[ch[x][i]]=1; q.push(ch[x][i]);23 }24 }25 }26 char str[150];27 int main(){28 scanf("%d%d",&n,&m); inc(i,1,n)scanf("%s",str+1),insert(str); ans=1; getfail();29 inc(i,1,m)ans=ans*26%mod; f[0][0]=1;30 inc(i,1,m)inc(j,0,sz)if(!val[j]&&f[i-1][j]){31 inc(k,0,25){32 int x=j; while(x&&!ch[x][k])x=fail[x]; f[i][ch[x][k]]=(f[i][ch[x][k]]+f[i-1][j])%mod;33 }34 }35 inc(i,0,sz)if(!val[i]){36 ans=(ans-f[m][i])%mod; if(ans<0)ans+=mod;37 }38 printf("%d",ans); return 0;39 }
20160621
bzoj1030[JSOI2007]文本產生器