• HDU-2825-Wireless Password(AC自动机, 状压DP)


    链接:

    https://vjudge.net/problem/HDU-2825

    题意:

    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.

    思路:

    先建立trie图, end记录以这个点结尾的额字符串标号, 二进制形式.
    同时节点的fail指针的也要一起合并过来.
    在考虑dp[i][j][k], 长度为i, 以j为结尾, 拥有k的字符串种类.
    由上往下更新, trie图上下一个节点, 同时合并结尾字符串累加答案.

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    //#include <memory.h>
    #include <queue>
    #include <set>
    #include <map>
    #include <algorithm>
    #include <math.h>
    #include <stack>
    #include <string>
    #include <assert.h>
    #include <iomanip>
    #include <iostream>
    #include <sstream>
    #define MINF 0x3f3f3f3f
    using namespace std;
    typedef long long LL;
    const LL MOD = 20090717;
    const LL MAXN = 110;
    const int MAXASCII = 26;
    
    struct TrieTree
    {
        int Next[MAXASCII];
        int end;
        int fail;
        void Clear()
        {
            memset(Next, 0, sizeof(Next));
            end = 0;
        }
    }tree[MAXN];
    
    char s[MAXN];
    LL Dp[26][110][1<<10];
    int n, m, k, cnt;
    
    void Insert(char *s, int x)
    {
        int len = strlen(s);
        int p = 0;
        for (int i = 0;i < len;i++)
        {
            if (tree[p].Next[s[i]-'a'] == 0)
                tree[p].Next[s[i]-'a'] = ++cnt, tree[cnt].Clear();
            p = tree[p].Next[s[i]-'a'];
        }
        tree[p].end |= 1<<x;
    }
    
    void BuildAC()
    {
        queue<int> que;
        for (int i = 0;i < MAXASCII;i++)
        {
            if (tree[0].Next[i] != 0)
            {
                tree[tree[0].Next[i]].fail = 0;
                que.push(tree[0].Next[i]);
            }
        }
        while (!que.empty())
        {
            int u = que.front();
            que.pop();
            tree[u].end |= tree[tree[u].fail].end;
            for (int i = 0;i < MAXASCII;i++)
            {
                if (tree[u].Next[i] != 0)
                {
                    tree[tree[u].Next[i]].fail = tree[tree[u].fail].Next[i];
                    que.push(tree[u].Next[i]);
                }
                else
                    tree[u].Next[i] = tree[tree[u].fail].Next[i];
            }
        }
    }
    
    int GetK(int val)
    {
        int cn = 0;
        for (int i = 0;i < m;i++)
        {
            if ((1<<i) & val)
                cn++;
        }
        return cn;
    }
    
    LL Cal()
    {
        memset(Dp, 0, sizeof(Dp));
        Dp[0][0][0] = 1;
        for (int i = 0;i < n;i++)
        {
            for (int j = 0;j <= cnt;j++)
            {
                for (int w = 0; w < (1<<m); ++w)
                {
                    if (Dp[i][j][w] == 0)
                        continue;
                    for (int t = 0;t < MAXASCII;t++)
                    {
                        Dp[i+1][tree[j].Next[t]][w|tree[tree[j].Next[t]].end] += Dp[i][j][w];
                        Dp[i+1][tree[j].Next[t]][w|tree[tree[j].Next[t]].end] %= MOD;
                    }
                }
            }
        }
        LL sum = 0;
        for (int i = 0;i <= cnt;i++)
        {
            for (int w = 0;w < (1<<m);w++)
            {
                if (GetK(w) >= k)
                    sum = (sum+Dp[n][i][w])%MOD;
            }
        }
        return sum;
    }
    
    int main()
    {
        while (~scanf("%d%d%d", &n, &m, &k))
        {
            if (n == 0 && m == 0 && k == 0)
                break;
            cnt = 0;
            tree[cnt].Clear();
            for (int i = 0;i < m;i++)
            {
                scanf("%s", s);
                Insert(s, i);
            }
            BuildAC();
            printf("%lld
    ", Cal());
        }
    
        return 0;
    }
    
  • 相关阅读:
    一款由张鹏老师录制的一周HOLD住HTML+CSS视频教程分享给大家
    一款LAMP兄弟连最近录制的《HTML5视频教程》此款视频不错哟!上吧
    一款HTML5的基础视频教程分享给大家,希望大家好好学习啊。
    分享一款由杨中科老师主讲的javascript视频教程,属于.NET课程是视频教程
    今天给大家带来的视频教程是LINUX视频教程,希望大伙能在里面学到你想要的!
    周一好亲们!今天还给大家分享的是Oracle视频教程,来自于传智播客!
    零晨了,为大家分享一套很好的javascript视频教程!喜欢的拿走啊。
    最新为大家整理的一套android视频教程,有兴趣的便宜可以去看看!
    .net的基础学习,.NET视频教程
    yii2 (not set), GridView
  • 原文地址:https://www.cnblogs.com/YDDDD/p/11639170.html
Copyright © 2020-2023  润新知