Description
JSOI交給隊員ZYX一個任務,編制一個稱之為“文本生成器”的電腦軟件:該軟件的使用者是一些低幼人群,
他們現在使用的是GW文本生成器v6版。該軟件可以隨機生成一些文章―――總是生成一篇長度固定且完全隨機的文章—— 也就是說,生成的文章中每個字節都是完全隨機的。如果一篇文章中至少包含使用者們了解的一個單詞,
那么我們說這篇文章是可讀的(我們稱文章a包含單詞b,當且僅當單詞b是文章a的子串)。但是,即使按照這樣的
標准,使用者現在使用的GW文本生成器v6版所生成的文章也是幾乎完全不可讀的?。ZYX需要指出GW文本生成器 v6生成的所有文本中可讀文本的數量,以便能夠成功獲得v7更新版。你能幫助他嗎?
Input
輸入文件的第一行包含兩個正整數,分別是使用者了解的單詞總數N (<= 60),GW文本生成器 v6生成的文本固
定長度M;以下N行,每一行包含一個使用者了解的單詞。這里所有單詞及文本的長度不會超過100,並且只可能包
含英文大寫字母A..Z
Output
一個整數,表示可能的文章總數。只需要知道結果模10007的值。
Sample Input
2 2
A
B
A
B
Sample Output
100
Solution
第一次做在AC自動機上跑DP的題……
之前做的好像都是亂搞
學長說AC自動機的DP都非常套路
大部分f[i][j]表示當前在節點j,且串長為i時的情況,
有時再加一維表示這個狀態里面包含了哪些東西
而且AC自動機的DP會經常讓你用矩陣乘法優化
那么對於這個題,我們可以先將AC自動機建立出來,然后搞一個簡單的容斥
用所有的情況減去不可讀的情況。
那么那些是不可讀的情況呢?當然就是跑不到單詞結尾節點的情況嘍……
定義f[i][j]表示當前在j點且串長為i時不經過單詞結尾的路徑條數
然后從父親往兒子轉移即可
注意如果一個單詞的后綴是一個可讀單詞(即fail指針指向可讀單詞的結尾節點)
那么這個單詞一定也是可讀的,我們就不能往這個單詞走了
話說之前我好像做過類似的不過沒有吸取教訓QvQ活該WA好久
之前做的好像都是亂搞
學長說AC自動機的DP都非常套路
大部分f[i][j]表示當前在節點j,且串長為i時的情況,
有時再加一維表示這個狀態里面包含了哪些東西
而且AC自動機的DP會經常讓你用矩陣乘法優化
那么對於這個題,我們可以先將AC自動機建立出來,然后搞一個簡單的容斥
用所有的情況減去不可讀的情況。
那么那些是不可讀的情況呢?當然就是跑不到單詞結尾節點的情況嘍……
定義f[i][j]表示當前在j點且串長為i時不經過單詞結尾的路徑條數
然后從父親往兒子轉移即可
注意如果一個單詞的后綴是一個可讀單詞(即fail指針指向可讀單詞的結尾節點)
那么這個單詞一定也是可讀的,我們就不能往這個單詞走了
話說之前我好像做過類似的不過沒有吸取教訓QvQ活該WA好久
Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<queue> 5 #define MOD (10007) 6 #define N (10005) 7 using namespace std; 8 9 int Son[N][26],End[N],Fail[N]; 10 int n,m,sz,f[105][N],ans; 11 char s[N]; 12 queue<int>q; 13 14 void Insert(char s[]) 15 { 16 int now=0,len=strlen(s); 17 for (int i=0; i<len; ++i) 18 { 19 int x=s[i]-'A'; 20 if (!Son[now][x]) Son[now][x]=++sz; 21 now=Son[now][x]; 22 } 23 End[now]|=1; 24 } 25 26 void Build_Fail() 27 { 28 for (int i=0; i<26; ++i) 29 if (Son[0][i]) 30 q.push(Son[0][i]); 31 while (!q.empty()) 32 { 33 int now=q.front(); 34 q.pop(); 35 for (int i=0; i<26; ++i) 36 { 37 if (!Son[now][i]) 38 { 39 Son[now][i]=Son[Fail[now]][i]; 40 continue; 41 } 42 End[Son[now][i]]|=End[Son[Fail[now]][i]]; 43 Fail[Son[now][i]]=Son[Fail[now]][i]; 44 q.push(Son[now][i]); 45 } 46 47 } 48 } 49 50 int main() 51 { 52 scanf("%d%d",&n,&m); 53 for (int i=1; i<=n; ++i) 54 scanf("%s",s),Insert(s); 55 Build_Fail(); 56 f[0][0]=1; 57 for (int i=1; i<=m; ++i) 58 for (int j=0; j<=sz; ++j) 59 for (int k=0; k<26; ++k) 60 if (!End[Son[j][k]]) 61 (f[i][Son[j][k]]+=f[i-1][j])%=MOD; 62 for (int i=0; i<=sz; ++i) 63 (ans+=f[m][i])%=MOD; 64 int sum=1; 65 for (int i=1; i<=m; ++i) 66 sum=sum*26%MOD; 67 printf("%d\n",(sum-ans+MOD)%MOD); 68 }