好题!搞了N久终于AC!
【题意】
给定N个字符集合和P个禁用的字符串,求长度为M的合法字符串个数。
【题解】
显然是AC自动机上的DP。
令dp[i][j]表示长度为i,状态为j的字符串个数。
按自动机的图转移即可,但要注意细节。
贡献几组数据。
50 50 10
qwertyuiop[]\asdfghjkl;'zxcvbnm,./ QWERTYUIOP{}|AS
aegaegu
etoijqt
tquqi
witowwt
zxcjnc
oeit
potieq
iojge
nvoq
piqper
ans=8881647922834867244791415981705771412427494861672253136057167374729235842468240763290
1 1 1
a
a
ans=0
5 10 3
abcde
abc
bc
c
ans=1048576
#include <iostream>
#include <queue>
using namespace std;
const int maxn=800,maxm=55,base=100000000,kind=55;
struct node
{
int sum,id;
node* ch[kind];
node* fail;
}a[maxn];
struct num
{
int g[20];
int len;
num()
{
memset(g,0,sizeof(g));
len=1;
}
}dp[maxm][maxn];
char s[maxm];
int dx[400];
int n,m,p,tot=0;
node* getroot()
{
tot++;
int i;
for (i=0;i<kind;i++)
a[tot].ch[i]=0;
a[tot].fail=0;
a[tot].id=tot;
a[tot].sum=0;
return &a[tot];
}
node* root=getroot();
node* getnode()
{
tot++;
int i;
for (i=0;i<kind;i++)
a[tot].ch[i]=0;
a[tot].fail=root;
a[tot].id=tot;
a[tot].sum=0;
return &a[tot];
}
void ins(char* s)
{
int i,k,len=strlen(s);
node* now=root;
for (i=0;i<len;i++)
{
k=dx[s[i]+128];
if (now->ch[k]==0)
now->ch[k]=getnode();
now=now->ch[k];
}
now->sum++;
}
void init()
{
int i;
char st[maxm];
scanf("%d%d%d\n",&n,&m,&p);
gets(s);
for (i=0;i<n;i++)
dx[s[i]+128]=i;
for (i=1;i<=p;i++)
{
scanf("%s",st);
ins(st);
}
}
queue<node*> q;
void build()
{
int i,k;
node* now,*ff;
q.push(root);
while (!q.empty())
{
now=q.front();
q.pop();
for (i=0;i<kind;i++)
if (now->ch[i]!=0)
{
q.push(now->ch[i]);
for (ff=now->fail;ff!=0;ff=ff->fail)
if (ff->ch[i]!=0)
{
now->ch[i]->fail=ff->ch[i];
if (ff->ch[i]->sum==1) now->ch[i]->sum=1;
break;
}
}
}
}
num operator +(num a,num b)
{
num c=num();
int i,t,k=0,len=max(a.len,b.len);
for (i=1;i<=len;i++)
{
t=a.g[i]+b.g[i]+k;
k=t/base;
c.g[i]=t%base;
}
while (k)
{
c.g[++len]=k%base;
k/=base;
}
c.len=len;
return c;
}
void DP()
{
int i,j,k;
dp[0][1].g[1]=1;
for (i=0;i<m;i++)
for (j=1;j<=tot;j++)
{
node* now=&a[j];
for (k=0;k<n;k++)
if (now->ch[k]!=0)
{
int ct=now->ch[k]->id;
if (now->ch[k]->sum==0) dp[i+1][ct]=dp[i+1][ct]+dp[i][j];
}
else
{
node* tmp=now->fail;
for (;tmp!=0;tmp=tmp->fail)
if (tmp->ch[k]!=0)
{
tmp=tmp->ch[k];
break;
}
if (tmp==0) tmp=root;
int ct=tmp->id;
if (tmp->sum==0) dp[i+1][ct]=dp[i+1][ct]+dp[i][j];
}
}
}
void print()
{
int i,j;
num ans=num();
for (i=1;i<=tot;i++)
ans=ans+dp[m][i];
j=ans.len;
printf("%d",ans.g[j]);
for (i=j-1;i>=1;i--)
{
if (ans.g[i]<base/10) printf("0");
if (ans.g[i]<base/100) printf("0");
if (ans.g[i]<base/1000) printf("0");
if (ans.g[i]<base/10000) printf("0");
if (ans.g[i]<base/100000) printf("0");
if (ans.g[i]<base/1000000) printf("0");
if (ans.g[i]<base/10000000) printf("0");
printf("%d",ans.g[i]);
}
printf("\n");
}
int main()
{
freopen("pin.txt","r",stdin);
freopen("pou.txt","w",stdout);
init();
build();
DP();
print();
return 0;
}