POJ 1625 Censored (Trie FIG && DP && precision)

Meaning of the questions:  given n-word character set and p illegal string, ask you to use the word structure length character set which is the word of the program several m How many?

Analysis: First construct a Trie convenience state transition, in which the step of POJ 2278 is the same, but the last state transition DP 2778 embodiment is the use of the transfer matrix, because it is necessary to construct the string length very long ! Only use the transfer matrix. This question but the length of string required configuration at most only 50 to be transferred using a common DP method. We define the DP [i] [j] is of length i character j is the end of the string number of kinds is many, then the state transition equation it is clear that DP [i + 1] [k ] + = DP [i] [ j] * G [j] [ k] this equation represents now k to j there is an edge and away from the k-step can be to j program number is G [j] [k] ( Trie FIG constructed out), so now DP [i + 1] [k] can be transferred quite clear from DP [i] [j] from the initial state to the DP DP [0] [0] = 0 && DP [0] [i] = 0.

note: 

① Because there is no requirement for modulo arithmetic answers, the answer may be large, because if p = 0, and m and n are maximum 50, the answer is 50 ^ 50, the need to use high precision.

② There may be more than 128 characters, that is, there is a negative case, the transformation 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", &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

 

Guess you like

Origin www.cnblogs.com/shuaihui520/p/11615523.html