题目地址:http://poj.org/problem?id=1625
题目意思:
给你一个字典,里面有n个不同的字符
然后给你p个不允许出现的字符串
要你求出在由字典里的字符组成的一个m长度的字符串不含禁止字符串的种数有多少
解题思路:
假设在一个AC自动机上,状态j的长度已经有i了,用dp[i][j]表示
那么dp[i+1][tmp] += dp[i][j] 其中tmp这个节点可以由j合法的转移(合法就是不会出现禁止的情况)
再就是本题的数据规模很大,50^50,所以要用大数
再就是要注意几个细节
比如最后大数的结果为0的话
或者是当上面说的j已经是非法点了,那么就不能跳转了
再就是本题输入的char可能会有到255,那么会出现负数,所以我用了hash的方法来重定向下标
下面上代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int maxnode = 120;
const int size=256;
int hash[size];
int wordn,m,p;
struct AC
{
int ch[maxnode][size];
int f[maxnode];
bool val[maxnode];
int sz;
void init()
{
sz=1;
memset(ch[0],-1,sizeof(ch[0]));
val[0]=false;
}
void insert(char *s)
{
int len = strlen(s);
int u=0;
for(int i=0;i<len;i++)
{
int c=hash[s[i]+128];
if(-1 == ch[u][c])
{
memset(ch[sz],-1,sizeof(ch[sz]));
val[sz]=false;
ch[u][c] = sz++;
}
u=ch[u][c];
}
val[u] = true;
}
void getfail()
{
queue<int> q;
for(int i=0;i<wordn;i++)
{
int u = ch[0][i];
if(-1!=u)
{
f[u]=0;
q.push(u);
}
else
ch[0][i]=0;
}
while(!q.empty())
{
int r=q.front();
q.pop();
//printf("q\n");
val[r] |= val[f[r]];
for(int i=0;i<wordn;i++)
{
int &v=ch[r][i];
if(-1!=v)
{
q.push(v);
f[v]=ch[f[r]][i];
}
else
{
v=ch[f[r]][i];
}
}
}
}
}ac;
struct bignumber
{
int a[100];
void init()
{
memset(a,0,sizeof(a));
}
void print()
{
int j=99;
while(a[j]==0)
j--;
if(j<0)
{
printf("0\n");
return ;
}
while(j>=0)
{
printf("%d",a[j]);
j--;
}
printf("\n");
}
};
void add(bignumber &x,bignumber y)
{
for(int i=0;i<99;i++)
{
x.a[i]+=y.a[i];
x.a[i+1]+=x.a[i]/10;
x.a[i]=x.a[i]%10;
}
}
bignumber dp[55][120];
void dp_ac()
{
memset(dp,0,sizeof(dp));
dp[0][0].a[0]=1;
for(int i=0;i<m;i++)
{
for(int j=0;j<ac.sz;j++)
{
if(ac.val[j])
continue;
for(int k=0;k<wordn;k++)
{
int tmp = ac.ch[j][k];
if(!ac.val[tmp] && !ac.val[j])
{
add(dp[i+1][tmp],dp[i][j]);
}
}
}
}
bignumber ans;
ans.init();
for(int i=0;i<ac.sz;i++)
{
add(ans,dp[m][i]);
}
ans.print();
}
int main()
{
while(~scanf("%d%d%d",&wordn,&m,&p))
{
ac.init();
char str[100];
getchar();
gets(str);
memset(hash,0,sizeof(hash));
for(int i=0;i<wordn;i++)
{
hash[str[i]+128]=i;
}
for(int i=0;i<p;i++)
{
gets(str);
ac.insert(str);
}
ac.getfail();
dp_ac();
}
return 0;
}