天天看點

bzoj 2553 [BeiJing2011]禁忌

​​http://www.elijahqi.win/archives/3222​​​

Description

Magic Land上的人們總是提起那個傳說:他們的祖先John在那個東方島嶼幫助Koishi與其姐姐Satori最終戰平。而後,Koishi恢複了讀心的能力……

如今,在John已經成為傳說的時代,再次造訪那座島嶼的人們卻發現Koishi遇到了新麻煩。

這次她遇到了Flandre Scarlet——她擁有可以使用禁忌魔法而不會受到傷害的能力。

為了說明什麼是禁忌魔法及其傷害,引入以下概念:

1.字母集A上的每個非空字元串對應了一個魔法。

其中A是包含了前alphabet個小寫字母的集合。

2.有一個集合T,包含了N個字母集A上的字元串

T中的每一串稱為一個禁忌串(Taboo string)

3.一個魔法,或等價地,其對應的串s因為包含禁忌而對使用者造成的傷害按以下方式确定:

把s分割成若幹段,考慮其中是禁忌串的段的數目,不同的分割可能會有不同的數目,其最大值就是這個傷害。

由于擁有了讀心的能力,Koishi總是随機地使用Flandre Scarlet的魔法,可以确定的是,她的魔法正好對應字母集A上所有長度為len的串。

但是,Flandre Scarlet所使用的一些魔法是帶有禁忌的,由于其自身特性,她可以使用禁忌魔法而不受到傷害,而Koishi就不同了。可憐的Koishi每一次使用對方的魔法都面臨着受到禁忌傷害的威脅。

你現在需要計算的是如果Koishi使用對方的每一個魔法的機率是均等的,那麼每一次随機使用魔法所受到的禁忌傷害的期望值是多少。

Input

第一行包含三個正整數N、len、alphabet。

接下來N行,每行包含一個串Ti,表示禁忌串。

Output

一個非負實數,表示所受到禁忌傷害的期望值。

Sample Input

2 4 2

aa

abb

Sample Output

0.75

【樣例1解釋】

一共有2^4 = 16種不同的魔法。

需要注意的是“aabb”的禁忌傷害是1而不是2。

HINT

100%的資料中N ≤ 5,len ≤109,1 ≤ alphabet ≤ 26。

在所有資料中,有不少于40%的資料中:N = 1。

資料保證每個串Ti的長度不超過15,并且不是空串。

資料保證每個Ti均僅含有前alphabet個小寫字母。

資料保證集合T中沒有相同的元素,即對任意不同的i和j,有Ti≠Tj。

【評分方法】

對于每一組資料,如果沒有得到正确的輸出(TLE、MLE、RTE、輸出格式錯誤等)得0分。

否則:設你的輸出是YourAns,标準輸出是StdAns:

記MaxEPS = max(1.0 , StdAns)×10-6

如果|YourAns – StdAns| ≤ MaxEPS則得10分,否則得0分。

即:你的答案需要保證相對誤差或絕對誤差不超過10-6。

Source

mdzz 矩陣乘法轉移忘記累加答案

考慮這個s是固定的怎麼做 相當于有很多線段 即給定的那n個字元串 求用最多的線段覆寫s能用多少個

那麼這道題把他給定的這些串建AC自動機

然後每次在AC自動機上貪心比對 如果比對到了一個就給我答案++ 然後使得我目前重新從頭開始比對

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ld long double
using namespace std;
int cnt=1,trans[100][26],fail[100],n,len,a;bool end[100];
inline void insert1(char *s){int p=1;
    for (int i=1,nxt;s[i];++i){
        if (!trans[p][s[i]-'a']) trans[p][s[i]-'a']=nxt=++cnt;
        else nxt=trans[p][s[i]-'a'];p=nxt; 
    }end[p]=1;
}
struct matrix{ld f[100][100];}tr,ans;
inline matrix multiply(const matrix &a,const matrix &b){
    matrix c;memset(c.f,0,sizeof(c.f));
    for (int i=1;i<=cnt;++i)
        for (int k=1;k<=cnt;++k)
            for (int j=1;j<=cnt;++j)    
                c.f[i][j]+=a.f[i][k]*b.f[k][j];
    return c;
}
inline void buildAC(){
    queue<int>q;q.push(1);for (int i=0;i<a;++i) trans[0][i]=1;
    while(!q.empty()){
        int x=q.front();q.pop();
        for (int i=0;i<a;++i){
            int &y=trans[x][i];
            if (!y) {y=trans[fail[x]][i];continue;}
            fail[y]=trans[fail[x]][i];q.push(y);end[y]|=end[fail[y]]; 
        }
    }
}
char s[100];
int main(){
    freopen("bzoj2553.in","r",stdin);
    scanf("%d%d%d",&n,&len,&a);ld v=(ld)1/a;
    for (int i=1;i<=n;++i) scanf("%s",s+1),insert1(s);
    buildAC();ans.f[1][1]=1;++cnt;
    for (int i=1;i<cnt;++i){
        for (int j=0;j<a;++j){
            int y=trans[i][j];
            if (end[y]) tr.f[i][1]+=v,tr.f[i][cnt]+=v;else tr.f[i][y]+=v;
        }
    }tr.f[cnt][cnt]=1;
    for (int t=len;t;t>>=1,tr=multiply(tr,tr)) if (t&1) ans=multiply(ans,tr);
    printf("%.10f\n",(double)ans.f[1][cnt]);
    return 0;
}