HDU2825 Wireless Password【AC自动机 + DP】

题目描述:

长度为n<=25的密码,至少包含m<=10个神奇单词中的k个(单词长度<=10),求所有可能的密码个数。

题目分析:

f [ i ] [ s ] [ j ] f[i][s][j] f[i][s][j]表示用了 i i i个字母,已经包含的神奇单词的状态为 s s s,当前在AC自动机上的 j j j号点的方案数。
转移为 f [ i + 1 ] [ s ∣ w o r d [ c h [ j ] [ c ] ] ] [ c h [ j ] [ c ] ] + = f [ i ] [ s ] [ j ] f[i+1][s|word[ch[j][c]]][ch[j][c]]+=f[i][s][j] f[i+1][sword[ch[j][c]]][ch[j][c]]+=f[i][s][j]。复杂度 O ( n m l e n 2 m ∗ 26 ) O(nmlen2^m*26) O(nmlen2m26),很多状态是0可以跳过。

Code:

#include<cstdio>
#include<cstring>
#define maxn 105
#define maxc 26
const int mod = 20090717;
int n,m,k;
char s[maxn];
struct ac_automaton{
	int ch[maxn][maxc],fail[maxn],cnt[maxn],tot,f[1025][maxn],g[1025][maxn];
	inline void init(){
		memset(ch,0,sizeof ch);memset(cnt,0,sizeof cnt);
		memset(f,0,sizeof f);
		tot=0;
	}
	inline void insert(char *s,int id){
		int len=strlen(s),r=0,v;
		for(int i=0;i<len;r=ch[r][v],i++) if(!ch[r][v=s[i]-'a']) ch[r][v]=++tot;
		cnt[r]|=(1<<id);
	}
	int Q[maxn],head,tail;
	inline void build(){
		Q[head=0]=0,tail=1;
		while(head<tail)
		{
			int r=Q[head++],c;
			for(int i=0;i<maxc;i++)
				if(c=ch[r][i]) fail[c]=r?ch[fail[r]][i]:0,Q[tail++]=c,cnt[c]|=cnt[fail[c]];
				else ch[r][i]=ch[fail[r]][i];
		}
	}
	inline void add(int &a,const int b){a=(a+b)%mod;}
	inline void solve(){
		int ans=0;
		f[0][0]=1;
		for(int l=1;l<=n;l++)
		{
			memset(g,0,sizeof g);
			for(int s=0;s<(1<<m);s++)
				for(int i=0;i<=tot;i++) if(f[s][i])
					for(int j=0;j<maxc;j++)
						add(g[s|cnt[ch[i][j]]][ch[i][j]],f[s][i]);
			memcpy(f,g,sizeof f);
		}
		for(int s=0;s<(1<<m);s++){
			int x=0;
			for(int i=0;i<m;i++) if(s&(1<<i)) x++;
			if(x>=k) for(int i=0;i<=tot;i++) add(ans,f[s][i]);
		}
		printf("%d\n",ans);
	}
}A;
int main()
{
	while(scanf("%d%d%d",&n,&m,&k),n)
	{
		A.init();
		for(int i=0;i<m;i++) scanf("%s",s),A.insert(s,i);
		A.build();
		A.solve();
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值