1. 程式人生 > >11468 Substring (AC自動機 + 概率dp)

11468 Substring (AC自動機 + 概率dp)

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <iostream>
#include <vector>
#include <map>
#include <queue>
using namespace std;

int get(char ch){
    if (ch >= 'a' && ch <= 'z'){
        return ch - 'a';
    }
    if (ch >= 'A' && ch <= 'Z'){
        return ch - 'A' + 26;
    }
    if (ch >= '0' && ch <= '9'){

        return ch - '0' + 52;
    }
}


const int maxn = 500;
const int maxm = 62;

char cmd[50];

double mp[128];
struct Trie{

    int L, root;
    int next[maxn][maxm];
    int fail[maxn];
    int flag[maxn];
    double dp[101][maxn];

    void init(){
        L = 0;
        root = newnode();
    }
    void insert(char* s){
        int len = strlen(s);
        int nod = root;
        for (int i = 0; i < len; ++i){
            int id = get(s[i]);
            if (next[nod][id] == -1){
                next[nod][id] = newnode();
            }
            nod = next[nod][id];
        }
        flag[nod] = 1;
    }
    int newnode(){
        for (int i = 0; i < maxm; ++i){
            next[L][i] = -1;
        }
        flag[L] = 0;
        return L++;
    }
    void bfs(){
        queue<int>q;
        fail[root] = root;

        for (int i = 0; i < maxm; ++i){
            if (next[root][i] == -1){
                next[root][i] = root;
            }
            else {
                fail[next[root][i] ] = root;
                q.push(next[root][i]);
            }
        }
        while(!q.empty()){
            int u = q.front(); q.pop();
            flag[u] |= flag[fail[u] ];
            for (int i = 0; i < maxm; ++i){
                if (next[u][i] == -1){
                    next[u][i] = next[fail[u] ][i];
                }
                else {
                    fail[next[u][i] ] = next[fail[u] ][i];
                    q.push(next[u][i]);
                }
            }
        }
    }
    void solve(int n){
        memset(dp,0,sizeof dp);
        dp[0][0] = 1.0;
        for (int i = 1; i <= n; ++i){
            for (int j = 0; j < L; ++j){
                if (dp[i-1][j] == 0) continue;
                for (int k = 0; k < maxm; ++k){
                    int nx = next[j][k];
                    if (flag[nx]) continue;
                    dp[i][nx] += dp[i-1][j] * mp[k];
                }
            }
        }
        double ans = 0;
        for (int i = 0; i < L; ++i){
            ans += dp[n][i];
        }
        printf("%.6f\n", ans);
    }


}ac;




int main(){


    int T;
    int ks = 0;
    scanf("%d",&T);
    while(T--){
        int n;
        scanf("%d", &n);
        memset(mp,0,sizeof mp);
        ac.init();
        for (int i = 0; i < n; ++i){
            scanf("%s", cmd);
            ac.insert(cmd);
        }
        ac.bfs();
        scanf("%d", &n);
        for (int i = 0; i < n; ++i){
            double x;
            scanf("%s%lf", cmd, &x);
            mp[get(cmd[0]) ] = x;
        }
        scanf("%d", &n);

        printf("Case #%d: ", ++ks);
        ac.solve(n);
    }
    return 0;
}