BZOJ 2553: [BeiJing2011]禁忌

一開始以爲期望好難啊QAQ
然後瞄了一下題解發現並不難? 1A 很舒服

建出自動機之後當然是用自動機節點來進行矩乘
算一下兩點間轉移概率什麼的就好

爲了統計答案 我們就弄多一個點 o=tot+1 設p=1/alphabet
轉移到的點如果已經是終點了 就讓他 連向o概率+=p 連向根的也+=p
然後a[o][o]=1來統計答案就好

還是不太懂就看代碼吧~
我的代碼簡直就是好看啊2333

#include<bits/stdc++.h>
#define me(a,x) memset(a,x,sizeof a)
using namespace std;
const int N=105;
inline int read(){
    int x=0,f=1; char ch=getchar();
    while(ch<'0' || ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0' && ch<='9'){x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();}
    return x*f;
}
int t[N][26],fail[N],tot;
bool v[N],bo[N]; char s[20];
void ins(){
    int x=0,len=strlen(s);
    for(int i=0;i<len;++i){
        int y=s[i]-'a';
        if(!t[x][y])t[x][y]=++tot;
        x=t[x][y];
    }v[x]=1;
}
int Q[N],m,o;
void bulid(){
    int he=0,ta=0;
    while(he<=ta){
        int x=Q[he++];
        for(int i=0;i<m;++i){
            int u=t[x][i],f=fail[x];
            if(!u){t[x][i]=t[f][i]; continue;}
            if(x)fail[u]=t[f][i]; else fail[u]=0;
            v[u]|=v[fail[u]],Q[++ta]=u;
        }
    }
}
struct mat{
    long double a[N][N];
    mat(){me(a,0);}
}a,ans;
inline mat operator*(mat &x,mat &y){
    mat z;
    for(int i=0;i<=o;++i)for(int j=0;j<=o;++j)for(int k=0;k<=o;++k)
        z.a[i][j]+=x.a[i][k]*y.a[k][j];
    return z;
}
void pre(){
    int he=0,ta=0; bo[0]=1; long double p=1.0/m;
    while(he<=ta){
        int x=Q[he++];
        for(int i=0;i<m;++i){
            int u=t[x][i];
            if(!bo[u])bo[u]=1,Q[++ta]=u;
            if(v[u])a.a[x][o]+=p,a.a[x][0]+=p;
            else a.a[x][u]+=p;
        }
    }
}
int main(){
    int n=read(),k=read(); m=read();
    for(int i=0;i<n;++i)scanf("%s",s),ins();
    bulid(); o=tot+1; pre();
    a.a[o][o]=1;
    for(int i=0;i<=o;++i) ans.a[i][i]=1;
    for(;k;k>>=1,a=a*a) if(k&1) ans=ans*a;
    printf("%.7lf\n",(double)ans.a[0][o]);
    return 0;
}
發佈了173 篇原創文章 · 獲贊 203 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章