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 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

/*
hdu 2825 aC自动机+状压dp

给你m个子串,求长度为n的主串中至少出现k个子串的方案数
首先通过AC自动机构建关系图. 然后用dp解决状态转移,需要知道用过哪些子串
因为k比较小,我们直接转换成二进制来记录当前状态包含了哪些子串。用ed对各子串进行标记

dp[i][j][t]就表示长度为i,当前位置上是j时,所包含子串的情况t

hhh-2016-04-24 17:13:36
*/
#include <iostream>
#include <vector>
#include <cstring>
#include <string>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <functional>
#include <map>
using namespace std;
#define lson  (i<<1)
#define rson  ((i<<1)|1)
typedef unsigned long long ll;
typedef unsigned int ul;
const int mod = 20090717;
const int INF = 0x3f3f3f3f;
int tot;
int dp[30][111][1<<10];

struct Matrix
{
    int len;
    int ma[111][111];
    Matrix() {};
    Matrix(int L)
    {
        len = L;
    }
};

struct Tire
{
    int nex[110][26],fail[110],ed[110];
    int root,L;
    int newnode()
    {
        for(int i = 0; i < 26; i++)
            nex[L][i] = -1;
        ed[L++] = 0;
        return L-1;
    }

    void ini()
    {
        L = 0,root = newnode();
    }

    int cal(char ch)
    {
        if(ch == ‘A‘)
            return 0;
        else if(ch == ‘C‘)
            return 1;
        else if(ch == ‘G‘)
            return 2;
        else if(ch == ‘T‘)
            return 3;
    }

    void inser(char buf[],int id)
    {
        int len = strlen(buf);
        int now = root;
        for(int i = 0; i < len; i++)
        {
            int ta = buf[i] - ‘a‘;
            if(nex[now][ta] == -1)
                nex[now][ta] = newnode();
            now = nex[now][ta];
        }
        ed[now]  |= (1<<id);
    }

    void build()
    {
        queue<int >q;
        fail[root] = root;
        for(int i = 0; i < 26; i++)
            if(nex[root][i] == -1)
                nex[root][i] = root;
            else
            {
                fail[nex[root][i]] = root;
                q.push(nex[root][i]);
            }
        while(!q.empty())
        {
            int now = q.front();
            q.pop();
            if(ed[fail[now]])
                ed[now] |= ed[fail[now]];
            for(int i = 0; i < 26; i++)
            {
                if(nex[now][i] == -1)
                    nex[now][i] = nex[fail[now]][i];
                else
                {
                    fail[nex[now][i]] = nex[fail[now]][i];
                    q.push(nex[now][i]);
                }
            }
        }
    }

    Matrix to_mat()
    {
        Matrix mat(L);
        memset(mat.ma,0,sizeof(mat.ma));
        for(int i = 0; i < L; i++)
        {
            for(int j = 0; j < 4; j++)
            {
                if(!ed[nex[i][j]])
                    mat.ma[i][nex[i][j]] ++;
            }
        }
        return mat;
    }
};

//Matrix mat;
Tire ac;
char buf[22];

void debug()
{
    Matrix t = ac.to_mat();
    for(int i = 0; i < t.len; i++)
    {
        for(int j = 0; j < 26; j++)
        {
            printf("%d ",t.ma[i][ac.nex[i][j]]);
        }
        printf("\n");
    }
}

int num[1<<10];

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]++;
    }
    int n,m,p;
    while(scanf("%d%d%d",&n,&m,&p) != EOF)
    {
        if(!n && !m && !p)
            break;
        ac.ini();
        for(int i = 0; i < m; i++)
        {
            scanf("%s",buf);
            ac.inser(buf,i);
        }
        ac.build();
        for(int i = 0; i <= n; i++)
        {
            for(int j = 0; j <ac.L; j++)
            {
                for(int k = 0; k < (1<<m); k++)
                    dp[i][j][k] = 0;
            }
        }
        dp[0][0][0] = 1;
        for(int i = 0; i < 2; i++)
        {
            for(int j = 0; j < ac.L; j++)
            {
                for(int t = 0; t < (1<<m); t++)
                {
                    if(dp[i][j][t] > 0)
                        for(int k = 0; k < 26; k++)
                        {
                            int nexi = i+1;
                            int nexj = ac.nex[j][k];
                            int nexk = (t|ac.ed[nexj]);
                            dp[nexi][nexj][nexk] = (dp[nexi][nexj][nexk] + dp[i][j][t])%mod;

                        }
                }
            }
        }
        int ans = 0;
        for(int j = 0; j < (1<<m); j++)
        {
            if(num[j] < p)
                continue;
            for(int i = 0; i < ac.L; i++)
                ans = (ans+dp[n][i][j])%mod;
        }
        printf("%d\n",ans);
    }
    return 0;
}

  

时间: 2024-10-24 05:26:08

hdu 2825 aC自动机+状压dp的相关文章

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

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 3247 AC自动+状压dp+bfs处理

Resource Archiver Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 100000/100000 K (Java/Others)Total Submission(s): 2382    Accepted Submission(s): 750 Problem Description Great! Your new software is almost finished! The only thing left to

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

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

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

hdu 4057 Rescue the Rabbit(AC自动机+状压dp)

题目链接:hdu 4057 Rescue the Rabbit 题意: 给出一些模式串,每个串有一定的价值,现在构造一个长度为M的串,问最大的价值为多少,每个模式串最多统计一次. 题解: 由于每个模式串最多统计一次,所以我们要考虑记录是否已经存在该串. 考虑dp[i][j][k]表示当前考虑到i的长度,存在的串的组合为j,在AC自动机上走到了k这个节点的状态. 然后转移一下就能将所有能到达的状态走到.然后取一个最大值就行了. 1 #include<bits/stdc++.h> 2 #defin

AC自动机+状压DP

HDU 2825 题目大义: 给定m个长度不超过10的单词,你需要构造一个长度为n的文本串,文本串包含的给定单词不小于k个,求方案数. 分析: 看完题目觉得像是数学题,需要一些容斥啥的算算(其实是瞎想,不知道怎么实现),最后也只会暴力搜索判断这种没分数的写法.其实是一道DP题,算是一种利用AC自动机做DP的套路,需要学会. 定义F[i][j][mask],表示当前文本串长度为i,匹配到了AC自动机上的第j个节点,已包含的单词集合为mask时的方案数.显然我们可以从j节点向下更新,继续枚举一个l字