sol
至少出现一次?这怎么(DP)?
然而:
至少出现一次的方案数=总方案数-一次都没有出现的方案数
所以就把给出的字符串当作是不合法字符然后跑(DP)就可以了。
code
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int N = 6005;
const int mod = 10007;
int n,m,tot,ch[26][N],fail[N],frb[N],dp[105][N];
char s[N];
queue<int>Q;
int fastpow(int a,int b)
{
int res=1;
while (b) {if (b&1) res=res*a%mod;a=a*a%mod;b>>=1;}
return res;
}
void Insert()
{
scanf("%s",s);int l=strlen(s),x=0;
for (int i=0;i<l;i++)
{
if (!ch[s[i]-'A'][x]) ch[s[i]-'A'][x]=++tot;
x=ch[s[i]-'A'][x];
}
frb[x]=1;
}
void Get_Fail()
{
for (int i=0;i<26;i++) if (ch[i][0]) Q.push(ch[i][0]);
while (!Q.empty())
{
int u=Q.front();Q.pop();
for (int i=0;i<26;i++)
if (ch[i][u]) fail[ch[i][u]]=ch[i][fail[u]],Q.push(ch[i][u]);
else ch[i][u]=ch[i][fail[u]];
frb[u]|=frb[fail[u]];
}
}
int DP()
{
dp[0][0]=1;
for (int i=1;i<=m;i++)
for (int j=0;j<=tot;j++)
if (!frb[j])
for (int k=0;k<26;k++)
if (!frb[ch[k][j]])
(dp[i][ch[k][j]]+=dp[i-1][j])%=mod;
int res=0;
for (int i=0;i<=tot;i++) (res+=dp[m][i])%=mod;
return res;
}
int main()
{
scanf("%d %d",&n,&m);
for (int i=1;i<=n;i++) Insert();
Get_Fail();
printf("%d
",(fastpow(26,m)-DP()+mod)%mod);
return 0;
}