BZOJ1030 AC自動機上的DP

2021-08-18 16:11:58 字數 1739 閱讀 8948

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 2a

b sample output

100

題意是給出一些字串,求長為m的包含某些其中串的字串的總數。

我們可以倒過來想,長度為m的字串共有26^m種可能性,如果我們減去不包含任何給定串的字串的個數,剩下的個數就是要求的答案。

所以我們可以先將所有給定的字串構建乙個ac自動機,然後進行dp。

我們設dp[i][j]表示dp到長度為i的串,且在ac自動機j節點上的值。我們可以清楚的知道我們要從dp[i][j]轉移到dp[i+1][p],其中p為下乙個位置。我們列舉k為a~z這26個字元,並且在ac自動機上查詢,如果從j往fail[j]跳,能跳到某些節點,有以該節點結尾的子串,則表示dp[i+1][j]是不可行的,因為如果這麼走會使最終的字串中出現題目給定的串。如果不存在這樣的點,就將dp[i+1][next[j][k]]加上dp[i][j],並直接將j變為next[j][k]即可。

最後用快速冪求出26^m,然後減去∑dp[m][x](x為ac自動機上所有點)。

#include

#define md 10007

using namespace std;

intread()

int n,m,cnt,q[10000],dp[105][10000],ans,tot;

string s;

struct nodef[10000];

int pows(int a,int b)

return base%md;

}void build(string s)

}f[pl].sum++;

}void fail()

}int main()

fail();

dp[0][0]=1;

for(int i=0;ifor(int j=0;j<=cnt;j++)

now=f[now].fail;

}if(flag) continue;

now=j;now=f[now].next[k];

dp[i+1][now]=(dp[i+1][now]+dp[i][j])%md;}}

tot=pows(26,m);

for(int i=0;i<=cnt;i++)

ans=(ans+dp[m][i])%md;

printf("%d",(tot-ans+md)%md);

return

0;}

(帶講解)bzoj1030 AC自動機 dp

第一道ac自動機上的dp 題意是給出一些字串,求長為m的字串包含這些的一共有多少個,字符集a z 首先運用補集轉換,轉而求不含這些串的個數,最後用26 m減掉就行 根據輸入的字串建立ac自動機 dp i j 表示當前考慮了i位,當前停留在ac自動機的j號節點 每一次可以由dp i j 轉移到dp i...

AC自動機 建立nlogn個AC自動機

string set queries 題意 給你3種操作,1 加入乙個串到集合中。2 刪除集合中的某乙個串 3 查詢集合中的字串在給定的字串種出現幾次。同乙個串可重複 解法 建立多個ac自動機,用二進位制分組來處理。加入給你21個串 分為 16 4 1,再新增乙個串的時候,即21 1,22 16 4...

AC自動機及字尾自動機

ac自動機是一種基於trie樹的演算法,其本質和kmp上的處理很相似。trie樹結構 kmp轉移思路 ac自動機組要由三個部分組成 trie樹的建立 fail指標的匹配 對ac自動機的詢問 每次建立自動機會有一次初始化 ac自動機類 struct node node結構體 struct ac voi...