BZOJ2553 [BeiJing2011]禁忌 【AC自动机 + dp + 矩乘优化】

题目链接

BZOJ2553

题解

话说在前,此题卡精度,最好开long double

先建\(AC\)自动机
求期望,逆着求,设\(f[i][j]\)为长度为\(i\)的串,当前匹配AC自动机\(j\)节点,之后能产生伤害的期望值
枚举转移,如果转移到一个单词节点,因为产生伤害的单词间不能相连,就直接跳回根节点

矩乘优化一下即可

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<cmath>
#include<iomanip>
#include<map>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long long int
using namespace std;
const int maxn = 80,maxm = 100005,INF = 1000000000;
inline int read(){
    int out = 0,flag = 1; char c = getchar();
    while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    return out * flag;
}
char s[6][20];
int n,L,A,len[6];
int ch[maxn][26],fail[maxn],val[maxn],cnt;
void ins(int p){
    int u = 0,id;
    for (int i = 1; i <= len[p]; i++){
        id = s[p][i] - 'a';
        u = ch[u][id] ? ch[u][id] : (ch[u][id] = ++cnt);
    }
    val[u] = true;
}
void dfs(int u,int f){
    if (val[f]) val[u] = true;
    for (int i = 0; i < A; i++)
        if (ch[u][i]) dfs(ch[u][i],u);
}
void getf(){
    queue<int> q;
    for (int i = 0; i < A; i++) if (ch[0][i]) q.push(ch[0][i]);
    int u,v;
    while (!q.empty()){
        u = q.front(); q.pop();
        for (int i = 0; i < A; i++){
            v = ch[u][i];
            if (!v){
                ch[u][i] = ch[fail[u]][i];
                continue;
            }
            fail[v] = ch[fail[u]][i];
            q.push(v);
        }
    }
}
struct Matrix{
    long double s[maxn][maxn];
    int n,m;
    Matrix(){cls(s);n = m = 0;}
}C,F;
inline Matrix operator *(const Matrix& a,const Matrix b){
    Matrix c;
    if (a.m != b.n) return c;
    c.n = a.n; c.m = b.m;
    for (int i = 0; i < c.n; i++)
        for (int j = 0; j < c.m; j++)
            for (int k = 0; k < a.m; k++)
                c.s[i][j] += a.s[i][k] * b.s[k][j];
    return c;
}
inline Matrix qpow(Matrix a,int b){
    Matrix re; re.n = re.m = a.n;
    for (int i = 0; i < re.n; i++) re.s[i][i] = 1;
    for (; b; b >>= 1,a = a * a)
        if (b & 1) re = re * a;
    return re;
}
int main(){
    n = read(); L = read(); A = read();
    REP(i,n){
        scanf("%s",s[i] + 1),len[i] = strlen(s[i] + 1);
        ins(i);
    }
    dfs(0,0);
    getf();
    C.n = C.m = cnt + 2; long double x = 1.0 / A;
    for (int i = 0; i <= cnt; i++){
        if (val[i]) continue;
        for (int j = 0; j < A; j++){
            if (val[ch[i][j]]){
                C.s[i][cnt + 1] += x;
                C.s[i][0] += x;
            }
            else {
                C.s[i][ch[i][j]] += x;
            }
        }
    }
    C.s[cnt + 1][cnt + 1] = 1;
    F.n = cnt + 2; F.m = 1;
    F.s[cnt + 1][0] = 1;
    Matrix Fn = qpow(C,L) * F;
    long double ans = Fn.s[0][0];
    cout << fixed <<setprecision(12) << ans<<endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Mychael/p/9115125.html