bzoj 2553: [BeiJing2011]禁忌 AC自动机+矩阵乘法

题目大意:

http://www.lydsy.com/JudgeOnline/problem.php?id=2553

题解:

利用AC自动机的dp求出所有的转移
然后将所有的转移储存到矩阵中,进行矩阵乘法即可

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
    x=0;char ch;bool flag = false;
    while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
    while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const int maxn = 88;
int maxc,n,m;
int ch[maxn][26],nodecnt;
bool danger[maxn];
inline void insert(char *s){
    int len = strlen(s),nw = 0;
    for(int i=0;i<len;++i){
        int c = s[i] - 'a';
        if(ch[nw][c] == 0){
            ch[nw][c] = ++ nodecnt;
        }
        nw = ch[nw][c];
    }danger[nw] = true;
}
int fail[maxn],q[maxn];
inline void build(){
    int l = 0,r = -1;
    for(int c=0;c<maxc;++c){
        if(ch[0][c]){
            fail[ch[0][c]] = 0;
            q[++r] = ch[0][c];
        }
    }
    while(l <= r){
        int u = q[l++];
        for(int c=0;c<maxc;++c){
            int t = ch[fail[u]][c];
            if(!ch[u][c]) ch[u][c] = t;
            else{
                danger[ch[u][c]] |= danger[t];
                fail[ch[u][c]] = t;
                q[++r] = ch[u][c];
            }
        }
    }
}
struct Matrix{
    int n,m;
    long double s[maxn][maxn];
    void clear(int n = 0,int m = 0){
        this->n = n;this->m = m;
        memset(s,0,sizeof s);
    }
    Matrix friend operator * (const Matrix &a,const Matrix &b){
        Matrix c;c.clear(a.n,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;
    }
};
Matrix ori,mul;
inline Matrix qpow(Matrix x,int p){
    Matrix ret;ret.clear(x.m,x.m);
    for(int i=0;i<x.m;++i) ret.s[i][i] = 1;
    for(;p;p>>=1,x=x*x) if(p&1) ret=ret*x;
    return ret;
}
char s[22];
int main(){
    read(n);read(m);read(maxc);
    for(int i=1;i<=n;++i){
        scanf("%s",s);
        insert(s);
    }build();
    ori.clear(1,nodecnt+2);ori.s[0][nodecnt+1] = 1.0;
    mul.clear(nodecnt+2,nodecnt+2);
    for(int i=0;i<=nodecnt;++i){
        for(int c=0;c<maxc;++c){
            if(danger[ch[i][c]]){
                mul.s[0][i] += 1.0/maxc;
                mul.s[nodecnt+1][i] += 1.0/maxc;
            }else{
                mul.s[ch[i][c]][i] += 1.0/maxc;
            }
        }
    }mul.s[nodecnt+1][nodecnt+1] = 1.0;
    Matrix ans = ori*qpow(mul,m);
    printf("%.10lf",((double)ans.s[0][0]));
    getchar();getchar();
    return 0;
}
posted @ 2017-03-04 06:19  Sky_miner  阅读(189)  评论(0编辑  收藏  举报