求一个串至少包含k个给定的串的方案数(k个串可相互覆盖-所以只能用AC自动机了)
状态压缩使每个串唯一(1<<i第i个串),防止重复加!(WA)
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<cstdlib> #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<set> #include<map> #include<list> #include<queue> #include<stack> #include<vector> #define tree int o,int l,int r #define lson o<<1,l,mid #define rson o<<1|1,mid+1,r #define lo o<<1 #define ro o<<1|1 #define pb push_back #define mp make_pair #define inf 0x7fffffff #define eps 1e-7 #define N 105 #define M 26 #define mod 20090717 using namespace std; int m,n,T,t,k; int ch[N][M]; int v[N]; int f[N],last[N],num; int d[N][M][1<<10],ans,ep[M]; void clear()//Trie树初始化 { num=1; ans=0; memset(d,-1,sizeof(d)); memset(ch[0],0,sizeof(ch[0])); memset(v,0,sizeof(v)); memset(last,0,sizeof(last)); } int idx(char c) { return c-'a'; } void insert(char str[],int val)//建Trie树 { int len=strlen(str); int u=0; for (int i=0; i<len; ++i ) { int c=idx(str[i]); if(!ch[u][c])//保存的是结点坐标 { memset(ch[num],0,sizeof(ch[num])); ch[u][c]=num++;// } u=ch[u][c]; } v[u]+=(1<<val);//唯一标记一个字符串(+=) } void getac() { queue<int> q;//保存的节点下标 f[0]=0; for (int c=0; c<M; ++c ) { int u=ch[0][c]; if(u)//不需要优化的else { q.push(u); f[u]=0; last[u]=v[u];//WA } } while(!q.empty()) { int r=q.front(); q.pop(); for (int c=0; c<M; ++c )//注意:c表示节点值,不是结点位置 { int u=ch[r][c]; if(u) { q.push(u); int s=f[r]; f[u]=ch[s][c]; last[u]=(v[u]+last[f[u]]); } else //重要优化 ch[r][c]=ch[f[r]][c]; } } } char str[20]; int bit(int x) { return x==0?0:(bit(x>>1)+(x&1)); } int dp(int u,int sub,int num) { if(sub==n) return bit(num)>=k; int &ans=d[u][sub][num]; if(ans!=-1)return ans; if(bit(num)>=k)//优化!!否则TLE(dp时也是需要优化的!) { ans=ep[n-sub];return ans; } ans=0; for(int i=0;i<26;i++) { int c=ch[u][i]; ans+=dp(c,sub+1,num+(last[c]^(last[c]&num))); ans%=mod; } return ans; } int main() { #ifndef ONLINE_JUDGE freopen("ex.in","r",stdin); #endif ep[0]=1; for(int i=1;i<=25;i++) ep[i]=(ep[i-1]*26)%mod; while(scanf("%d%d%d%*c",&n,&m,&k)==3) { if(!n&&!m&&!k)return 0; clear(); int i=0; while(m--) { scanf("%s",str); insert(str,i++); } getac(); printf("%d\n",dp(0,0,0)); } return 0; }