【 bzoj 2553 】 [BeiJing2011]禁忌 - AC自動機+矩陣乘法

  將自動機建出來之後就可以得到一個轉移矩陣,在沒有兩個串不能重疊的條件下直接跑矩乘就可以了。但是現在有這個條件,我們就新加一個點表示轉移到的單詞節點會轉移到這裏面去,然後這個點連出的邊只有自己且邊權爲1。還要注意的是,一個節點的fail點是單詞節點的話那麼這個點也要標記成單詞節點(終態),因爲他是禁位,也要轉移到那個新點。

#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 --)
#define For(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];

arr val , fail;
int n , len , m , tot;
int go[maxn][27];
char str[maxn];

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

void input() {
    n = rd() , len = rd() , m = rd() , tot = 1;
    rep (i , 1 , n) scanf("%s" , str + 1) , ins(str , i);
}

std::queue<int> Q;

inline void build() {
    For (c , 0 , m) {
        int u = go[1][c];
        if (!u) go[1][c] = 1;
        else Q.push(u) , fail[u] = 1;
    }
    while (!Q.empty()) {
        int u = Q.front() ; Q.pop();
        For (c , 0 , m) {
            int v = go[u][c] , f = go[fail[u]][c];
            if (!v) {
                go[u][c] = f;
                continue;
            }
            Q.push(v);
            fail[v] = f , val[v] |= val[f];
        }
    }
}

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

inline void Pow() {
    B = A , A.clear();
    rep (i , 0 , tot) A[i][i] = 1;
    while (len) {
        if (len & 1) A *= B;
        B *= B , len >>= 1;
    }
}

void solve() {
    build();
    long double pp = 1.0 / m;
    rep (i , 1 , tot) For (c , 0 , m) if (val[go[i][c]])
        A[i][0] += pp , A[i][1] += pp;
    else
        A[i][go[i][c]] += pp;
    A[0][0] = 1;
//  A.print();
    Pow();
    printf("%.6Lf\n" , A[1][0]);
//  A.print();
}

int main() {
    #ifndef ONLINE_JUDGE
        freopen("data.txt" , "r" , stdin);
    #endif
    input();
    solve();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章