【AC自动机】【状压dp】hdu2825 Wireless Password

f(i,j,S)表示当前字符串总长度为i,dp到AC自动机第j个结点,单词集合为S时的方案数。

要注意有点卡常数,注意代码里的注释。

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
queue<int>q;
#define MOD 20090717;
int child[111][26],fail[111],size,f[30][111][1100],tag[111];
void Insert(char S[],int id)
{
    int len=strlen(S);
    int now=0;
    for(int i=0;i<len;++i)
      {
        if(!child[now][S[i]-‘a‘])
          child[now][S[i]-‘a‘]=size++;
        now=child[now][S[i]-‘a‘];
      }
    tag[now]|=(1<<id);
}
void build()
{
    fail[0]=-1;
    q.push(0);
    while(!q.empty())
      {
        int U=q.front(); q.pop();
        for(int i=0;i<26;++i)
          if(child[U][i])
            {
              int V=fail[U];
              while(V!=-1)
                {
                  if(child[V][i])
                    {
                      fail[child[U][i]]=child[V][i];
                      break;
                    }
                  V=fail[V];
                }
              if(V==-1)
                fail[child[U][i]]=0;
              tag[child[U][i]]|=tag[fail[child[U][i]]];
              q.push(child[U][i]);
            }
          else if(U)
            child[U][i]=child[fail[U]][i];
      }
}
void Init()
{
    memset(child,0,sizeof(child));
    memset(fail,0,sizeof(fail));
    memset(tag,0,sizeof(tag));
    size=1;
}
int n,m,K;
bool check(int x)
{
	int res=0;
	for(int i=0;i<m;++i)
	  res+=((x>>i)&1);
	return res>=K;
}
int main()
{
	//freopen("hdu2825.in","r",stdin);
	char s[13];
	while(1)
	  {
	  	scanf("%d%d%d",&n,&m,&K);
	  	if(n==0 && m==0 && K==0)
	  	  break;
	  	Init();
	  	for(int i=0;i<m;++i)
	  	  {
	  	  	scanf("%s",s);
	  	  	Insert(s,i);
	  	  }
	  	build();
		for(int i=0;i<=n;++i)
	  	  for(int j=0;j<size;++j)
	  	    for(int k=0;k<(1<<m);++k)
	  		  f[i][j][k]=0;//用memset也许会TLE
	  	f[0][0][0]=1;
	  	for(int i=0;i<n;++i)
	  	  for(int j=0;j<size;++j)
	  	    for(int k=0;k<(1<<m);++k)
	  	      {
	  	      	if(!f[i][j][k])//不加会TLE
	  	      	  continue;
	  	      	for(int l=0;l<26;++l)
	  	    	  f[i+1][child[j][l]][k|tag[child[j][l]]]=
					(f[i+1][child[j][l]][k|tag[child[j][l]]]+f[i][j][k])%MOD;
	  	      }

		int ans=0;
		for(int i=0;i<(1<<m);++i)
		  if(check(i))
		    for(int j=0;j<size;++j)
		      ans=(ans+f[n][j][i])%MOD;
		printf("%d\n",ans);
	  }
	return 0;
}
时间: 2024-10-29 19:06:10

【AC自动机】【状压dp】hdu2825 Wireless Password的相关文章

hdu 2825 aC自动机+状压dp

Wireless Password Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5640    Accepted Submission(s): 1785 Problem Description Liyuan lives in a old apartment. One day, he suddenly found that there

poj 1699 Best Sequence(AC自动机+状压DP)

题目链接:poj 1699 Best Sequence 题目大意:给定N个DNA序列,问说最少多长的字符串包含所有序列. 解题思路:AC自动机+状压DP,先对字符串构造AC自动机,然后在dp[s][i]表示匹配了s,移动到节点i时候的最短步数. #include <cstdio> #include <cstring> #include <queue> #include <vector> #include <iostream> #include &

【HDU3341】 Lost&#39;s revenge (AC自动机+状压DP)

Lost's revenge Time Limit: 5000MS Memory Limit: 65535KB 64bit IO Format: %I64d & %I64u Description Lost and AekdyCoin are friends. They always play "number game"(A boring game based on number theory) together. We all know that AekdyCoin is t

HDU 3341 Lost&#39;s revenge(AC自动机+状压DP)

Lost's revenge Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submission(s): 4548    Accepted Submission(s): 1274 Problem Description Lost and AekdyCoin are friends. They always play "number game"(A bor

hdu 2825 Wireless Password(AC自动机+状压DP)

题目链接:hdu 2825 Wireless Password 题目大意:N,M,K,M个字符串作为关键码集合,现在要求长度为N,包含K个以上的关键码的字符串有多少个. 解题思路:AC自动机+dp,滚动数组,因为关键码个数不会超过10个,所以我们用二进制数表示匹配的状态.dp[i][j][k] 表示到第i个位置,j节点,匹配k个字符串. #include <cstdio> #include <cstring> #include <queue> #include <

[AC自动机+状压dp] hdu 2825 Wireless Password

题意: 给n,m,k ,再给出m个单词 问长度为n的字符串,至少在m个单词中含有k个的组成方案有多少种. 思路: 由于m最大是10,所以可以采取状压的思想 首先建立trie图,在每个单词的结束节点标记一个mark=(1<<id),id为单词的编号 然后需要注意的,对于每个节点,应该顺着fail指针遍历一遍, 把所有的mark取一个并集. 因为就是如果单词出现包含的话,比如 she和he 我拿了she,其实等于两个都拿了. dp[i][j][k]  i步在节点j状态k的方案数 然后就是一个四重循

hdu2825---Wireless Password(AC自动机+状压dp)

Wireless Password Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4688 Accepted Submission(s): 1433 Problem Description Liyuan lives in a old apartment. One day, he suddenly found that there was a

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

题目链接:hdu_2825_Wireless Password 题意: 给你m个串,问长度为n至少含k个串的字符串有多少个 题解: 设dp[i][j][k]表示考虑到长度为i,第j个自动机的节点,含有k这个压缩状态的方案数,然后DP下去就行了 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;i++) 3 using namespace std; 4 5 const int mod=20090717; 6 cons

[AC自动机+状压dp] hdu 4534 郑厂长系列故事——新闻净化

题意:中文的题目,意思就是说有很多串,每个串都有权值,权值为999的串必须出现,-999的串必须不出现.权值在-999~999之间. 然后必须出现的串不超过8个.然后给一个全为小写目标串,问最少需要删除多少个字母才能够保证必须出现的串都出现,次数一样保证权值最大.输出次数和权值. 然后根据样例,那些必须出现的串,其实权值是0. 思路: 很明显一开始建自动机构成trie图,但是需要注意的就是mark和sum的更新.个人是把所有中间的节点的sum全部赋值成了-inf. 接着只有8个必须出现的串,所以

POJ1699 Best Sequence(AC自动机+状压DP)

题目,包含所有的给定的n个DNA片段的序列的最短长度. 裸的AC自动机上的DP题. dp[S][u]表示已经包含的DNA片段集合为S,且当前后缀状态是自动机第u个结点的最短长度 dp[0][0]=0 我为人人+队列轻松转移.. 1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<algorithm> 5 using namespace std; 6 #define INF (