【 bzoj 1444 】 [Jsoi2009]有趣的遊戲 - AC自動機+矩陣乘法

  假設現在建好了一個AC自動機,那麼接受一個串相當於從根節點走到單詞節點。對應到這道題上,每走一步是有權值的(概率),就相當於無向圖一樣。這樣只要把鄰接矩陣建出來然後自乘一定次數就可以了。
  因爲精度要求不太高,所以自乘個63次就完全夠了233333

#include <bits/stdc++.h>
#define rep(i,a,b) for (int i = a , _ = b ; i <= _ ; i ++)
#define per(i,a,b) for (int i = a , _ = b ; i >= _ ; i --)

inline int rd() {
    char c = getchar();
    while (!isdigit(c)) c = getchar() ; int x = c - '0';
    while (isdigit(c = getchar())) x = x * 10 + c - '0';
    return x;
}

const int maxn = 207;

typedef int arr[maxn];

int n , m , tot , l;

arr val , pos , p , q , fail;

double prob[maxn];

char str[maxn][maxn];

int go[maxn][11];

inline void ins(char *s , int id) {
    int u = 1;
    for (char *_ = s + 1 ; *_ ; _ ++) {
        int c = *_ - 'A' + 1;
        if (!go[u][c]) go[u][c] = ++ tot;
        u = go[u][c];
    }
    val[u] = id , pos[id] = u;
}

std::queue<int> Q;

inline void build() {
    rep (c , 1 , m) {
        int u = go[1][c];
        if (u) Q.push(u) , fail[u] = 1;
        else go[1][c] = 1;
    }
    while (!Q.empty()) {
        int r = Q.front() ; Q.pop();
        rep (c , 1 , m) {
            int u = go[r][c];
            if (!u) { go[r][c] = go[fail[r]][c] ; continue ; }
            Q.push(u);
            int v = fail[r];
//          while (v && !go[v][c]) v = fail[v];
            fail[u] = go[v][c];
        }
    }
}

void input() {
    n = rd() , l = rd() , m = rd() , tot = 1;
    rep (i , 1 , m) p[i] = rd() , q[i] = rd() , prob[i] = (double) p[i] / q[i];
    rep (i , 1 , n) scanf("%s" , str[i] + 1) , ins(str[i] , i);
}

struct matrix {
    double a[maxn][maxn];
    matrix() { memset(a , 0 , sizeof a); }
    inline double* operator[](int x) {
        return a[x];
    }
    inline void clear() {
        rep (i , 1 , tot) rep (j , 1 , tot) a[i][j] = 0;
    }
    inline void operator=(matrix &t) {
        rep (i , 1 , tot) rep (j , 1 , tot) a[i][j] = t[i][j];
    }
    inline void print() {
        rep (i , 1 , tot) rep (j , 1 , tot) printf("%.2lf%c" , a[i][j] , j == tot ? '\n' : ' ');
        puts("==========");
    }
}A , B;

inline void mul() {
    B = A;
//  A.print();
    A.clear();
    rep (i , 1 , tot) rep (j , 1 , tot) rep (k , 1 , tot)
        A[i][j] += B[i][k] * B[k][j];
}

void solve() {
    build();
    rep (i , 1 , tot) if (val[i])
        A[i][i] = 1.0;
    else
        rep (c , 1 , m)
            A[i][go[i][c]] += prob[c];
    rep (t , 0 , 63)
        mul();
    rep (i , 1 , n) printf("%.2lf\n" , A[1][pos[i]]);
}

int main() {
    #ifndef ONLINE_JUDGE
        freopen("data.txt" , "r" , stdin);
    #endif
    input();
    solve();
    return 0;
}
發佈了135 篇原創文章 · 獲贊 6 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章