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;
    }
  • 相关阅读:
    Poj 1742 Coins(多重背包)
    Poj 2350 Above Average(精度控制)
    求二进制数中1的个数
    Poj 1659 Distance on Chessboard(国际象棋的走子规则)
    Poj 2411 Mondriaan's Dream(压缩矩阵DP)
    Poj 2136 Vertical Histogram(打印垂直直方图)
    Poj 1401 Factorial(计算N!尾数0的个数——质因数分解)
    poj 2390 Bank Interest(计算本利和)
    Poj 2533 Longest Ordered Subsequence(LIS)
    Poj 1887 Testing the CATCHER(LIS)
  • 原文地址:https://www.cnblogs.com/liuxin13/p/4758136.html
Copyright © 2011-2022 走看看