HDU 2825 Wireless Password

給定m個模式串,求至少包含k個模式串長度爲n的目標串的種數MOD20090717。end數組記錄爲模式串下標的二進制數,然後利用狀態壓縮dp來求解,dp[i][j][k],i爲當前串長度,j爲當前結點狀態,s爲包含串狀態。最後答案爲dp[n][i][j],i爲枚舉的所有結點,j爲包含串轉態大於等於k時的值,代碼如下

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
const int MOD=20090717;

int N,M,P;
struct Tree
{
	int next[300][26],end[300],fail[300];
	int L,root;
	int newnode()
	{
		for(int i=0;i<26;i++)
		{
			next[L][i]=-1;
		}
		end[L++]=0;
		return L-1;
	}
	void init()
	{
		L=0;
		root=newnode();
	}
	void insert(char *s,int pow)
	{
		int len=strlen(s);
		int p=root;
		for(int i=0;i<len;i++)
		{
			int id=s[i]-'a';
			if(next[p][id]==-1)
			{
				next[p][id]=newnode();
			}
			p=next[p][id];
		}
		end[p]|=(1<<pow);
	}
	void build()
	{
		queue<int>q;
		int p=root;
		fail[root]=root;
		for(int i=0;i<26;i++)
		{
			if(next[p][i]==-1)
			{
				next[p][i]=root;
			}
			else
			{
				fail[next[p][i]]=root;
				q.push(next[p][i]);
			}
		}
		while(!q.empty())
		{
			p=q.front();
			q.pop();
			end[p]|=end[fail[p]];
			for(int i=0;i<26;i++)
			{
				if(next[p][i]==-1)
				{
					next[p][i]=next[fail[p]][i];
				}
				else
				{
					fail[next[p][i]]=next[fail[p]][i];
					q.push(next[p][i]);
				}
			}
		}
	}
	void query(char *s)
	{
		int len=strlen(s);
		int p=root,ans=0;
		for(int i=0;i<len;i++)
		{
			int id=s[i]-'a';
			p=next[p][id];
			int temp=p;
			while(temp!=root)
			{
				if(end[temp])
				{
					ans+=end[temp];
					end[temp]=0;
				}
				temp=fail[temp];
			}
		}
	}
	void debug()
    {
        for(int i = 0;i < L;i++)
        {
            printf("id = %3d,fail = %3d,end = %3d,chi = [",i,fail[i],end[i]);
            for(int j = 0;j < 26;j++)
                printf("%2d",next[i][j]);
            printf("]\n");
        }
    }
};

Tree ac;
int num[3000];
char s[110];
int dp[30][110][3000];

void solve()
{
	int knum=(1<<M);
	for(int i=0;i<=N;i++)
	{
		for(int j=0;j<ac.L;j++)
		{
			for(int k=0;k<knum;k++)
			dp[i][j][k]=0;
		}
	}
	dp[0][0][0]=1;
	for(int i=0;i<N;i++)
	{
		for(int j=0;j<ac.L;j++)
		{
			for(int k=0;k<knum;k++)
			{
				if(dp[i][j][k]>0)
				{
				for(int l=0;l<26;l++)
				{
					int newi=i+1;
					int newj=ac.next[j][l];
					int newk=(k|ac.end[newj]);
					dp[newi][newj][newk]+=dp[i][j][k];
					dp[newi][newj][newk]%=MOD;
				}
				}
			}
		}
	}
	int ans=0;
	for(int i=0;i<knum;i++)
	{
		if(num[i]<P) continue;
		for(int j=0;j<ac.L;j++)
		{
			ans=(ans+dp[N][j][i])%MOD;
		}
	}
	printf("%d\n",ans);
}
int main()
{
	for(int i=0;i<(1<<10);i++)
	{
		num[i]=0;
		for(int j=0;j<10;j++)
		{
			if(i&(1<<j)) num[i]++;
		}
	}
	while(~scanf("%d %d %d",&N,&M,&P))
	{
		if(N==0&&M==0&&P==0) break;
		ac.init();
		for(int i=0;i<M;i++)
		{
			scanf("%s",s);
			ac.insert(s,i);
		}
		ac.build();
	//	ac.debug();
		solve();
	}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章