Wireless Password - HDU 2825(ac自动机+状态压缩)

题目大意:有个人想破解他邻居的密码,他邻居告诉了一些关于这个密码的信息,并且给他一个单词集合,他用这些信息判断一下最少有多少种密码。

1->, 所有的密码都是有小写字母组成。

2->,密码的长度是 n (1<= n <=25)。

3->,密码至少包含 k 种字符集里面的单词。

比如,给集合{"she", "he"},单词长度是3,最少包含两个单词的密码,很明显只能是“she”(题目表述的不清楚)。

 

分析:因为要统计记录到达每个点时候经过多少种不同的单词,所以需要用一种方法来保存这些信息,开一个数组来判重貌似是个很容易想到的办法,不过考虑时间复杂度的问题,建议还是不要这么干,因为字符集合的数量很少,只有10,所以我们可以使用状态压缩来保存这些信息,而且转移状态时候也很方便操作,不过有点需要注意,一定要把遍历子节点放在最内层循环,这样再遍历每一种状态的时候发先有0的情况可以continue一下,否则超时超的哇哇的.......

 

代码如下:

==========================================================================

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;

const int MAXN = 107;
const int MaxSon = 26;
const int Mod = 20090717;
const int oo = 1e9+7;

struct Ac_Trie
{
    int next[MAXN][MaxSon];
    int Fail[MAXN], End[MAXN];
    int cnt, root;

    int newnode()
    {
        for(int i=0; i<MaxSon; i++)
            next[cnt][i] = -1;
        Fail[cnt] = End[cnt] = false;

        return cnt++;
    }
    void InIt()
    {
        cnt = 0;
        root = newnode();
    }

    void Insert(char s[], int t)
    {
        int now = root;

        for(int i=0; s[i]; i++)
        {
            int k = s[i]-‘a‘;

            if(next[now][k] == -1)
                next[now][k] = newnode();
            now = next[now][k];
        }

        End[now] = 1<<t;
    }
    void GetFial()
    {
        queue<int>Q;
        int now = root;

        for(int i=0; i<MaxSon; i++)
        {
            if(next[now][i] == -1)
                next[now][i] = root;
            else
            {
                Fail[next[now][i]] = root;
                Q.push(next[now][i]);
            }
        }

        while(Q.size())
        {
            now = Q.front();
            Q.pop();

            for(int i=0; i<MaxSon; i++)
            {
                if(next[now][i] == -1)
                    next[now][i] = next[Fail[now]][i];
                else
                {
                    Fail[next[now][i]] = next[Fail[now]][i];
                    Q.push(next[now][i]);
                }
            }

            End[now] |= End[Fail[now]];
        }
    }
};
Ac_Trie ac;

int Find(int i)
{
    int k=0;

    while(i)
    {
        if(i % 2)
            k++;
        i /= 2;
    }

    return k;
}

int main()
{
    int N, M, K;

    int sum[1024] ={0};

    for(int i=0; i<1024; i++)
        sum[i] = Find(i);

    while(scanf("%d%d%d", &N, &M, &K), N+M+K)
    {
        char s[MAXN];
        ac.InIt();

        for(int i=0; i<M; i++)
        {
            scanf("%s", s);
            ac.Insert(s, i);
        }

        ac.GetFial();

        int dp[2][MAXN][1024] = {0}, op=0, Len = 1<<M;
        dp[1][0][0] = 1;

        while(N--)
        {
            memset(dp[op], 0, sizeof(dp[op]));

            for(int i=0; i<ac.cnt; i++)
            for(int k=0; k<Len; k++)
            {///把k放中间优化一下...否则超时
                if(dp[op^1][i][k] == 0)
                    continue;

                for(int j=0; j<MaxSon; j++)
                {
                    (dp[op][ac.next[i][j]][k|ac.End[i]] += dp[op^1][i][k])%=Mod;
                }
            }

            op ^= 1;
        }

        int ans = 0;

        for(int i=0; i<ac.cnt; i++)
        for(int j=0; j<Len; j++)
        {
            if(sum[j] >= K || sum[ac.End[i]|j] >= K)
            {
                ans += dp[op^1][i][j];
                ans %= Mod;
            }
        }

        printf("%d\n", ans);
    }

    return 0;
}
时间: 2024-08-29 01:52:44

Wireless Password - HDU 2825(ac自动机+状态压缩)的相关文章

hdu 4057 AC自动机+状态压缩dp

http://acm.hdu.edu.cn/showproblem.php?pid=4057 Problem Description Dr. X is a biologist, who likes rabbits very much and can do everything for them. 2012 is coming, and Dr. X wants to take some rabbits to Noah's Ark, or there are no rabbits any more.

HDU 4511 (AC自动机+状态压缩DP)

题目链接:  http://acm.hdu.edu.cn/showproblem.php?pid=4511 题目大意:从1走到N,中间可以选择性经过某些点,比如1->N,或1->2->N,但是某些段路径(注意不是某些条)是被禁止的.问从1->N的最短距离. 解题思路: AC自动机部分: 如果只是禁掉某些边,最短路算法加提前标记被禁的边即可. 但是本题是禁掉指定的路段,所以得边走边禁,需要一个在线算法. 所以使用AC自动机来压缩路段,如禁掉的路段是1->2->3,那么in

HDU 2825 Wireless Password (AC自动机 + 状态压缩DP)

题目链接:Wireless Password 解析:给 m 个单词构成的集合,统计所有长度为 n 的串中,包含至少 k 个单词的方案数. AC自动机 + 状态压缩DP. DP[i][j][k]:长度为i的字符串匹配到状态j且包含k个magic word的可能字符串个数. AC代码: #include <algorithm> #include <iostream> #include <cstdio> #include <queue> #include <

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

题意:这个题目和HDU2457有点类似,都是AC自动机上的状态dp,题意就是给你只含有'A','T','C','G',四个字符的子串和文本串,问你文本串如何排列才可以使得文本串中包含有更多的模式串 解题思路:我们知道了 有 num[0] 个 'A', num[1] 个 ‘T’, num[2] 个 ‘C’,num[3] 个‘G’, 我们的可以知道暴力的思路就是把所有的文本串都枚举出来然后一一匹配.我们膜拜了一下春哥以后,就可以有以下思路:  把一个串的信息压缩一下,把具有同样个数字符的串看成是同一

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

hdu 4758 Walk Through Squares(AC自动机+状态压缩DP)

题目链接:hdu 4758 Walk Through Squares 题意: 给你一个n*m的网格,现在你要从(1,1)走到(n,m),每次只能向右走或者向下走,走完后会形成一个包含R,D的序列,这个序列必须要包含题目给出的两个字符串,问有多少种方案. 题解: 由于要从(1,1)走到(n,m),所以这个形成的字符串包含R和D的数量是一定的. 现在考虑dp[u][i][j][k],表示包含两种串的组合状态,走了i个D,走了j个R,走到了k这个AC自动机的节点的方案数,然后dp一下就行了.复杂度为O

POJ 3691 (AC自动机+状态压缩DP)

题目链接:  http://poj.org/problem?id=3691 题目大意:给定N的致病DNA片段以及一个最终DNA片段.问最终DNA片段最少修改多少个字符,使得不包含任一致病DNA. 解题思路: 首先说一下AC自动机在本题中的作用. ①字典树部分:负责判断当前0~i个字符组成的串是否包含致病DNA,这部分靠字典树上的cnt标记完成. ②匹配部分:主要依赖于匹配和失配转移关系的计算,这部分非常重要,用来构建不同字符间状态压缩的转移关系(代替反人类的位运算). 这也是必须使用AC自动机而

【HDU3341】AC自动机状态压缩DP,或者说hash枚举DP,-------出题人卡常数都是狗!!!!!

题意:给若干种个串,再给个主串,然后把主串打乱顺序,使得包含子串尽量多(一种可以有多个,两个之间可以部分重叠).如第一组数据,ACGT,包含AC.CG.GT,三个,输出3.第二组数据A1A2A3,包含A1A2和A2A3两个"AA",答案为2. 其实我并没有AC.我被卡常数TLE了...实在不想写这种没意义的东西了. 贴代码,待填坑. #include <queue> #include <cstdio> #include <cstring> #incl

hdu4758AC自动机+状态压缩DP

http://acm.hdu.edu.cn/showproblem.php?pid=4758 Problem Description On the beaming day of 60th anniversary of NJUST, as a military college which was Second Artillery Academy of Harbin Military Engineering Institute before, queue phalanx is a special l