[JSOI2007]文本生成器
这题就是那种著名的AC自动机+dp题,算法唯一,如果你不会AC自动机,出门左转[传送门]。
这题当中的那些单词就相当于AC自动机模板中的模式串,只不过这题当中是要求满足“包含至少一个模式串的”文本串而已。
所以先把模式串放到 trie \texttt{trie} trie 树上,然后用AC自动机的 build() \texttt{build()} build() 函数把 f a i l fail fail 指针构造出来,并把 c h [ ] [ ] ch[][] ch[][] 数组进化为一条永通路,以便避免文本串匹配时一个模式串到结尾了没有地方可走的尴尬。
以上都是对模板的解说。 对于这题,我们发现“包含至少一个”这样的约束条件,就想到 答案 = = =整体 − - −剩余,先求出一个模式串都不包含的文本串数,然后求出没有约束条件下文本串有 2 6 m 26^m 26m 种,就可以得出答案。
因为要求一个模式串都不包含的文本串数,所以 insert(s) \texttt{insert(s)} insert(s) 的时候在有字符串结尾的节点 x x x 上注 m k [ x ] = 1 mk[x]=1 mk[x]=1,如下:
void insert(char*s){
int n=strlen(s+1),p=1;
for(int i=1;i<=n;i++){
int c=s[i]-'A'+1;
if(!ch[p][c]) ch[p][c]=++cnt;
p=ch[p][c];
}
mk[p]=1;
}
又因为如果一个字符串的后缀是模式串,那么它也不能出现在文本串中,所以在构造AC自动机 f a i l fail fail 指针的时候要令 m k [ x ] ∣ = m k [ f a i l