HDU2825AC自动机+状压

//我感觉这题不如叫你不看代码就不知道题干在说啥,强烈吐槽

Liyuan lives in a old apartment. One day, he suddenly found that there was a wireless network in the building. Liyuan did not know the password of the network, but he got some important information from his neighbor. He knew the password consists only of lowercase letters ‘a‘-‘z‘, and he knew the length of the password. Furthermore, he got a magic word set, and his neighbor told him that the password included at least k words of the magic word set (the k words in the password possibly overlapping).

For instance, say that you know that the password is 3 characters long, and the magic word set includes ‘she‘ and ‘he‘. Then the possible password is only ‘she‘.

Liyuan wants to know whether the information is enough to reduce the number of possible passwords. To answer this, please help him write a program that determines the number of possible passwords.

Input

There will be several data sets. Each data set will begin with a line with three integers n m k. n is the length of the password (1<=n<=25), m is the number of the words in the magic word set(0<=m<=10), and the number k denotes that the password included at least k words of the magic set. This is followed by m lines, each containing a word of the magic set, each word consists of between 1 and 10 lowercase letters ‘a‘-‘z‘. End of input will be marked by a line with n=0 m=0 k=0, which should not be processed.

Output

For each test case, please output the number of possible passwords MOD 20090717.

Sample Input

10 2 2
hello
world
4 1 1
icpc
10 0 0
0 0 0

Sample Output

2
1
14195065

http://blog.csdn.net/braketbn/article/details/50650341   //参考的代码

-------------------------------手写的代码

#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,k,dp[30][108][1100],cnt[1100];
const int mod=20090717;
struct AC
{
    int ch[108][26],fail[108],val[108],sz,rt;
    void init()
    {
        sz=rt=0;
        memset(ch[rt],-1,sizeof(ch[rt]));
    }
    void insert(char *str,int c)
    {
        int u=rt,len=strlen(str);
        for(int i=0; i<len; ++i)
        {
            if(ch[u][str[i]-‘a‘]==-1)
            {
                ++sz;
                memset(ch[sz],-1,sizeof(ch[sz]));
                val[sz]=0;
                ch[u][str[i]-‘a‘]=sz;
            }
            u=ch[u][str[i]-‘a‘];
        }
        val[u]=1<<c;
    }
    void build()
    {
        queue<int>Q;
        int u=rt;
        for(int i=0; i<26; ++i)
        {
            if(ch[u][i]==-1) ch[u][i]=rt;
            else
            {
                fail[ch[u][i]]=rt;
                Q.push(ch[u][i]);
            }
        }
        while(!Q.empty())
        {
            u=Q.front();
            Q.pop();
            val[u]|=val[fail[u]];
            for(int i=0; i<26; ++i)
            {
                if(ch[u][i]==-1) ch[u][i]=ch[fail[u]][i];
                else
                {
                    fail[ch[u][i]]=ch[fail[u]][i];
                    Q.push(ch[u][i]);
                }
            }
        }
    }
} ac;
char s[55];
int main()
{
    for(int i=0; i<1024; ++i) cnt[i]=__builtin_popcount(i);//黑科技
    while(scanf("%d%d%d",&n,&m,&k),n||m||k)
    {
        ac.init();
        for(int i=0; i<m; ++i)
        {
            scanf("%s",s);
            ac.insert(s,i);
        }
        ac.build();
        memset(dp,0,sizeof(dp));
        dp[0][0][0]=1;
        int ed=1<<m;
        for(int i=0; i<=n; ++i) for(int j=0; j<=ac.sz; ++j) for(int k=0; k<ed; ++k)
                {
                    if(!dp[i][j][k]) continue;
                    for(int l=0; l<26; ++l)
                    {
                        int u=ac.ch[j][l];
                        dp[i+1][u][ac.val[u]|k]+=dp[i][j][k];
                        dp[i+1][u][ac.val[u]|k]%=mod;
                    }
                }
        int ans=0;
        for(int i=0; i<=ac.sz; ++i) for(int j=0; j<ed; ++j) if(cnt[j]>=k)
                    ans=(ans+dp[n][i][j])%mod;
        printf("%d\n",ans);
    }
}

时间: 2024-10-28 15:12:35

HDU2825AC自动机+状压的相关文章

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 &

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

【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

[BZOJ1559]密码 AC自动机+状压

问题 K: [JSOI2009]密码 时间限制: 1 Sec  内存限制: 64 MB 题目描述 众所周知,密码在信息领域起到了不可估量的作用.对于普通的登陆口令,唯一的破解 方法就是暴力破解一逐个尝试所有可能的字母组合,但这是一项很耗时又容易被发现的工 作.所以,为了获取对方的登陆口令,在暴力破解密码之前,必须先做大量的准备工作.经 过情报的搜集,现在得到了若干有用信息,形如: “我观察到,密码中含有字符串***.” 例如,对于一个10位的密码以及观察到的字符串hello与world,可能的密

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

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

[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的方案数 然后就是一个四重循

HDU4057 Rescue the Rabbit(AC自动机+状压DP)

题目大概是给几个DNA片段以及它们各自的权值,如果一个DNA包含某个片段那么它的价值就加上这个片段的权值,同时包含多个相同DNA片段也只加一次,问长度l的DNA可能的最大价值. 与HDU2825大同小异. dp[i][j][S]表示长度i(自动机转移i步).后缀状态为自动机第j个结点.包含的DNA片段为集合S 的DNA最大价值 dp[0][0][0]=0 我为人人转移,从dp[i][j][S]向ATCG四个方向更新dp[i+1][j'][S'] 注意的是要用滚动数组,不然要开上百兆数组. 用滚动

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 <

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 (