bzoj 1030 文本生成器
题目大意:
生成一个长度为n的字符串,使它包含给出串中的一个
求这个生成串的方案数
思路:
dp i j表示匹配到i位,trie树上第j个节点的方案数
可以得到dp方程,dp i j 可以转移到 dp i+1 ch[j]
记录一下结尾处的节点
然后用总方案数-所有匹配不到的
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<cstring> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #define inf 2139062143 10 #define ll long long 11 #define MAXN 6010 12 #define MOD 10007 13 using namespace std; 14 inline int read() 15 { 16 int x=0,f=1;char ch=getchar(); 17 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 18 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 19 return x*f; 20 } 21 int n,dp[110][MAXN],m,tot,sz,ans; 22 char s[110]; 23 bool ed[MAXN]; 24 struct Trie {int fail,ch[26];}tr[MAXN]; 25 void insert(char *c,int len) 26 { 27 int pos=0; 28 for(int i=1;i<=len;i++) 29 { 30 if(!tr[pos].ch[c[i]-'A']) tr[pos].ch[c[i]-'A']=++sz; 31 pos=tr[pos].ch[c[i]-'A']; 32 } 33 ed[pos]=1; 34 } 35 void build() 36 { 37 queue <int> q; 38 for(int i=0;i<26;i++) if(tr[0].ch[i]) q.push(tr[0].ch[i]); 39 while(!q.empty()) 40 { 41 int k=q.front();q.pop(); 42 for(int i=0;i<26;i++) 43 if(tr[k].ch[i]) tr[tr[k].ch[i]].fail=tr[tr[k].fail].ch[i],q.push(tr[k].ch[i]); 44 else tr[k].ch[i]=tr[tr[k].fail].ch[i]; 45 ed[k]+=ed[tr[k].fail]; 46 } 47 } 48 int main() 49 { 50 n=read(),m=read(); 51 for(int i=1;i<=n;i++) scanf("%s",s+1),insert(s,strlen(s+1)); 52 build(); 53 dp[0][0]=tot=1; 54 for(int i=1;i<=m;i++) (tot*=26)%=MOD; 55 for(int i=1;i<=m;i++) 56 for(int j=0;j<=sz;j++) 57 { 58 if(ed[j]) continue; 59 for(int k=0;k<26;k++) (dp[i][tr[j].ch[k]]+=dp[i-1][j])%=MOD; 60 } 61 for(int i=0;i<=sz;i++) if(!ed[i]) (ans+=dp[m][i])%=MOD; 62 printf("%d",(tot-ans+MOD)%MOD); 63 }
orz没写主函数里忘了写build调了一年