HDOJ-2825 AC自动机DP+位运算..
原创
©著作权归作者所有:来自51CTO博客作者zzyzzy12的原创作品,请联系作者获取转载授权,否则将追究法律责任
题目是要求最少出现k种模式串...开始我看成k个了..囧..k种的话可以用2^k-1的整数可以描述出模式串出现的任意情况...也就是将每个模式串出现否看成二进制的1,0...题目中模式串最多10个..所以模式串存在状态最多1023种...
先用AC自动机构造Trie图...这个已经很模板很模板了..值得注意的是在构造时给每个点我称为data的值..代表从0点出发到这个点的串的后缀子串能是哪些模式串..为了保证完备性..应该将其fail的情况继承下来..这个过程举例子..假设当前点包含1,3号串..而其fail包含1,2号串...那么当前点就应该包含1,2,3号串..用二进制的角度看...当前串point[h].data=101..其fail: point[point[h].fail].data=011...而当前串应该变成point[h].data=111...这实际上就是二进制的或运算了..
dp时每个状态可以用三个值确定...1.当前长度,2.当前点标号.3.当前点标号下包含哪些串,也就是个十进制表示的二进制数..Trie图中每个点是状态点..有向边是转移方向..转移时同样也是通过二进制的或运算判断是当前状态转移到下个状态包含哪些串..
由于每个长度p的状态只于p-1长度的状态有关...所以可以用滚动数组来节约空间...
结果的话..找出所有包含模式串>k情况的..将这些dp值都加起来...O了~
Program:
#include<iostream>
#include<stdio.h>
#include<queue>
using namespace std;
struct node1
{
int son[26],fail,data;
char w;
}point[102];
int n,m,k,dp[2][102][1025];
char s[12];
queue<int> myqueue;
bool used[105];
int ok(int x)
{
int a=0;
while (x)
{
a+=x%2;
x/=2;
}
return a;
}
int main()
{
int i,j,h,len,p,x,num,ans,t;
while (~scanf("%d%d%d\n",&n,&m,&k))
{
if (!n && !m && !k) break;
memset(point,0,sizeof(point));
num=0;
for (i=0;i<m;i++)
{
scanf("%s",s);
len=strlen(s);
h=0;
for (j=0;j<len;j++)
{
if (!point[h].son[s[j]-'a'])
{
point[h].son[s[j]-'a']=++num;
point[num].w=s[j];
}
h=point[h].son[s[j]-'a'];
}
point[h].data=1<<i;
}
while (!myqueue.empty()) myqueue.pop();
for (i=0;i<26;i++)
if (point[0].son[i]) myqueue.push(point[0].son[i]);
while (!myqueue.empty())
{
h=myqueue.front();
myqueue.pop();
point[h].data|=point[point[h].fail].data;
for (i=0;i<26;i++)
{
p=point[h].fail;
while (p && !point[p].son[i]) p=point[p].fail;
point[point[h].son[i]].fail=point[p].son[i];
if (!point[h].son[i])
point[h].son[i]=point[p].son[i];
else
myqueue.push(point[h].son[i]);
}
}
memset(dp[0],0,sizeof(dp[0]));
dp[0][0][0]=1;
p=0;
t=(1<<m)-1;
while (n--)
{
p=1-p;
memset(dp[p],0,sizeof(dp[p]));
memset(used,false,sizeof(used));
used[0]=true;
myqueue.push(0);
while (!myqueue.empty())
{
h=myqueue.front();
myqueue.pop();
for (j=0;j<=t;j++)
if (dp[1-p][h][j])
for (i=0;i<26;i++)
{
if (!used[point[h].son[i]])
{
myqueue.push(point[h].son[i]);
used[point[h].son[i]]=true;
}
x=j|point[point[h].son[i]].data;
dp[p][point[h].son[i]][x]+=dp[1-p][h][j];
dp[p][point[h].son[i]][x]%=20090717;
}
}
}
ans=0;
for (j=0;j<=t;j++)
if (ok(j)>=k)
for (i=0;i<=num;i++) ans=(ans+dp[p][i][j])%20090717;
printf("%d\n",ans);
}
return 0;
}