您的位置:首页 > 其它

hdu_2825_Wireless Password(AC自动机+状压DP)

2016-08-29 16:44 357 查看

题目链接:hdu_2825_Wireless Password

题意:

给你m个串,问长度为n至少含k个串的字符串有多少个

题解:

设dp[i][j][k]表示考虑到长度为i,第j个自动机的节点,含有k这个压缩状态的方案数,然后DP下去就行了

#include<bits/stdc++.h>
#define F(i,a,b) for(int i=a;i<=b;i++)
using namespace std;

const int mod=20090717;
const int AC_N=10*51,tyn=26;//数量乘串长,类型数
struct AC_automation{
int tr[AC_N][tyn],cnt[AC_N],Q[AC_N],fail[AC_N],tot;
inline int getid(char x){return x-'a';}
void nw(){cnt[++tot]=0,fail[tot]=0;memset(tr[tot],0,sizeof(tr[tot]));}
void init(){tot=-1,fail[0]=-1,nw();}
void insert(char *s,int ids,int x=0){
for(int len=strlen(s),i=0,w;i<len;x=tr[x][w],i++)
if(!tr[x][w=getid(s[i])])nw(),tr[x][w]=tot;
cnt[x]|=1<<ids;//串尾标记
}
void build(int head=1,int tail=0){
for(int i=0;i<tyn;i++)if(tr[0][i])Q[++tail]=tr[0][i];
while(head<=tail)for(int x=Q[head++],i=0;i<tyn;i++)
if(tr[x][i])fail[tr[x][i]]=tr[fail[x]][i],Q[++tail]=tr[x][i],cnt[tr[x][i]]|=cnt[tr[fail[x]][i]];
else tr[x][i]=tr[fail[x]][i];
}
}AC;

char s[111];
int dp[26][111][1<<11],n,m,k,ans;

inline int getans(int s,int an=0)
{
F(i,0,9)if((s>>i)&1)an++;
return an;
}

int main()
{
while(~scanf("%d%d%d",&n,&m,&k)&&(n||m||k))
{
AC.init(),ans=0;
F(i,0,m-1)scanf("%s",s),AC.insert(s,i);
AC.build();
memset(dp,0,sizeof(dp)),dp[0][0][0]=1;
F(i,0,n-1)F(j,0,AC.tot)for(int k=0;k<(1<<m);++k)
if(dp[i][j][k]!=0)F(ii,0,25)
{
int *p=&dp[i+1][AC.tr[j][ii]][k|AC.cnt[AC.tr[j][ii]]];
*p=(*p+dp[i][j][k])%mod;
}
F(i,0,AC.tot)for(int j=0;j<(1<<m);j++)if(getans(j)>=k)ans=(ans+dp
[i][j])%mod;
printf("%d\n",ans);
}
return 0;
}
View Code

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: