zoukankan      html  css  js  c++  java
  • POJ 1625 Censored ( Trie图 && DP && 高精度 )

    题意 : 给出 n 个单词组成的字符集 以及 p 个非法串,问你用字符集里面的单词构造长度为 m 的单词的方案数有多少种?

    分析 : 与 POJ 2778 非常相似的一道题目,如果没有做过就尝试去了解一下,再回过头来看这道题就轻松很多了,是一类题型。先构造出 Trie 图方便进行状态转移,这与在 POJ 2278 中的步骤是一样的,只不过最后的DP状态转移方式 2778 是利用了矩阵进行转移的,那是因为需要构造的串的长度非常长!只能利用矩阵转移。但是这道题需要构造的串的长度最多也就只有 50 ,可以利用普通的DP方法进行转移。我们定义 DP[i][j] 为以长度为 i 以字符 j 为结尾的串的种类数是多少,那么状态转移方程很显然就是 DP[i+1][k] += DP[i][j] * G[j][k] 这个方程表示现在 k 到 j 有一条边并且从k 走一步可以到 j 的方案数是 G[j][k] ( Trie 图构建出来的 ),那么现在 DP[i+1][k] 就很明显可以从 DP[i][j] 转移而来,DP的初始状态为 DP[0][0] = 0 && DP[0][i] = 0。

    注意 : 

    ① 因为没有要求对答案进行求模运算,答案可能很大,因为如果 p = 0,而n 和 m 都达到最大的50,那么答案就是 50^50,所以需要用到高精度。

    ② 字符可能有超过 128 的,也就是有负数情况,用map转化

    #include<string.h>
    #include<stdio.h>
    #include<iostream>
    #include<queue>
    #include<map>
    using namespace std;
    const int Max_Tot = 111;
    const int Letter = 256;
    int G[111][111], n;
    map<int, int> mp;
    struct bign{
        #define MAX_B (100)
        #define MOD (10000)
        int a[MAX_B], n;
        bign() { a[0] = 0, n = 1; }
        bign(int num)
        {
            n = 0;
            do {
                a[n++] = num % MOD;
                num /= MOD;
            } while(num);
        }
        bign& operator= (int num)
        { return *this = bign(num); }
        bign operator+ (const bign& b) const
        {
            bign c = bign();
            int cn = max(n, b.n), d = 0;
            for(int i = 0, x, y; i < cn; i++)
            {
                x = (n > i) ? a[i] : 0;
                y = (b.n > i) ? b.a[i] : 0;
                c.a[i] = (x + y + d) % MOD;
                d = (x + y + d) / MOD;
            }
            if(d) c.a[cn++] = d;
            c.n = cn;
            return c;
        }
        bign& operator+= (const bign& b)
        {
            *this = *this + b;
            return *this;
        }
        bign operator* (const bign& b) const
        {
            bign c = bign();
            int cn = n + b.n, d = 0;
            for(int i = 0; i <= cn; i++)
                c.a[i] = 0;
            for(int i = 0; i < n; i++)
            for(int j = 0; j < b.n; j++)
            {
                c.a[i + j] += a[i] * b.a[j];
                c.a[i + j + 1] += c.a[i + j] / MOD;
                c.a[i + j] %= MOD;
            }
            while(cn > 0 && !c.a[cn-1]) cn--;
            if(!cn) cn++;
            c.n = cn;
            return c;
        }
        friend ostream& operator<< (ostream& _cout, const bign& num)
        {
            printf("%d", num.a[num.n - 1]);
            for(int i = num.n - 2; i >= 0; i--)
                printf("%04d", num.a[i]);
            return _cout;
        }
    };
    struct Aho{
        struct StateTable{
            int Next[Letter];
            int fail, flag;
        }Node[Max_Tot];
        int Size;
        queue<int> que;
    
        inline void init(){
            while(!que.empty()) que.pop();
            memset(Node[0].Next, 0, sizeof(Node[0].Next));
            Node[0].fail = Node[0].flag = 0;
            Size = 1;
        }
    
        inline void insert(char *s){
            int now = 0;
            for(int i=0; s[i]; i++){
                int idx = mp[s[i]];
                if(!Node[now].Next[idx]){
                    memset(Node[Size].Next, 0, sizeof(Node[Size].Next));
                    Node[Size].fail = Node[Size].flag = 0;
                    Node[now].Next[idx] = Size++;
                }
                now = Node[now].Next[idx];
            }
            Node[now].flag = 1;
        }
    
        inline void BuildFail(){
            Node[0].fail = 0;
            for(int i=0; i<n; i++){
                if(Node[0].Next[i]){
                    Node[Node[0].Next[i]].fail = 0;
                    que.push(Node[0].Next[i]);
                }else Node[0].Next[i] = 0;///必定指向根节点
            }
            while(!que.empty()){
                int top = que.front(); que.pop();
                if(Node[Node[top].fail].flag) Node[top].flag = 1;
                for(int i=0; i<n; i++){
                    int &v = Node[top].Next[i];
                    if(v){
                        que.push(v);
                        Node[v].fail = Node[Node[top].fail].Next[i];
                    }else v = Node[Node[top].fail].Next[i];
                }
            }
        }
    
        inline void BuildMap(){
            for(int i=0; i<Size; i++)
                for(int j=0; j<Size; j++)
                    G[i][j] = 0;
    
            for(int i=0; i<Size; i++){
                for(int j=0; j<n; j++){
                    if(!Node[ Node[i].Next[j] ].flag)
                        G[i][Node[i].Next[j]]++;
                }
            }
        }
    }ac;
    
    #define MAX_M (55)
    bign dp[MAX_M][Max_Tot];
    
    char s[51];
    int main(void)
    {
        int m, p;
        while(~scanf("%d %d %d
    ", &n, &m, &p)){
            mp.clear();
            gets(s);
            int len = strlen(s);
            for(int i=0; i<len; i++)
                mp[s[i]] = i;
    
            ac.init();
            for(int i=0; i<p; i++){
                gets(s);
                ac.insert(s);
            }
            ac.BuildFail();
            ac.BuildMap();
    
            for(int i=0; i<=m; i++)
                for(int j=0; j<ac.Size; j++)
                    dp[i][j] = bign();
    
            dp[0][0] = 1;
            for(int i=0; i<m; i++)
            for(int j=0; j<ac.Size; j++){
                for(int k=0; k<ac.Size; k++){
                    dp[i+1][k] += dp[i][j] * G[j][k];
                }
            }
    
            bign ans = bign();
    
            for(int i=0; i<ac.Size; i++)
                ans += dp[m][i];
    
            cout<<ans<<endl;
        }
        return 0;
    }
    View Code
  • 相关阅读:
    谈我们为什么学不好编程2——你是否已进入“等死模式”?
    JSP使用SmartUpload实现文件上传
    内核模块编程练习
    Vue++:Vue中 关于$emit的用法
    Vue++:Vue 脚手架在vue.config.js文件中配置scss全局变量
    Vue++:Vuecli3.0 脚手架搭建项目
    Java++:七个开源的 Spring Boot 前后端分离项目,一定要收藏!
    MySQL++:SQL 优化的15个小技巧
    RabbitMQ++:RabbitMQ 的队列(Queue)的参数及其含义
    Vue++:Vue 二级路由不显示页面问题
  • 原文地址:https://www.cnblogs.com/qwertiLH/p/7631515.html
Copyright © 2011-2022 走看看