zoukankan      html  css  js  c++  java
  • Wireless Password

    题目大意:有个人想破解他邻居的密码,他邻居告诉了一些关于这个密码的信息,并且给他一个单词集合,他用这些信息判断一下最少有多少种密码。
    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
    ", ans);
        }
    
        return 0;
    }
  • 相关阅读:
    2017 多校联合训练 8 题解
    2017 多校联合训练 7 题解
    2017 多校联合训练 6 题解
    2017 多校联合训练 5 题解
    2017 多校联合训练 4 题解
    windows 安装python
    pygame 使用
    python 发布
    面向对象的思维方法
    python 基础
  • 原文地址:https://www.cnblogs.com/liuxin13/p/4758136.html
Copyright © 2011-2022 走看看