第一道ac自動機上的dp
題意是給出一些字串,求長為m的字串包含這些的一共有多少個,字符集a-z
首先運用補集轉換,轉而求不含這些串的個數,最後用26^m減掉就行
根據輸入的字串建立ac自動機
dp[i][j]表示當前考慮了i位,當前停留在ac自動機的j號節點
每一次可以由dp[i][j]轉移到dp[i+1][k],k是列舉第i+1為後作為j的兒子在ac自動機上的編號
列舉k,就是第i+1為填什麼,然後進行下列操作:
首先看看這位能不能填k,判斷方法是從j開始向fail[j]跳,看是不是有乙個j有乙個k兒子,並且k兒子上還有結束標記,只要有乙個就證明如果i+1位填k就會讓整個字串出現ac自動機上的字串,所以不能填k
如果能放,再看看要修改哪個dp陣列。
還是從j開始向fail[j]跳,如果j有k這個兒子就直接修改dp[i+1][j的k兒子]就好
每次修改要對修改目標加上dp[i][j]
答案是所有dp[m][x](x是所有ac自動機上的節點)的和
** 陣列名稱:
fail:失敗指標
danger:結束標記
tr:trie樹
q:佇列
#include
#include
#include
#include
#include
#define md 10007
using namespace std;
char ch[1000];
int fail[6010],dp[1200][6010],f,ans;
inttr[6010][30],trcnt,danger[6010],i,j,n,m,q[6010],anss=1;
void insert() //建立trie樹
danger[now]=1;
}void acmach() //跑出fail陣列
}}int main()
acmach();
dp[0][1]=1; //初始化
for (i=0;i<=m-1;i++)
for (j=1;j<=trcnt;j++)
now=fail[now];
}if (f==1) continue; //不能放直接跳過
now=j;
while (!tr[now][k]) now=fail[now]; //j向fail[j]跳直到有k兒子
now=tr[now][k];
dp[i+1][now]=(dp[i+1][now]+dp[i][j])%md; //修改}}
for (i=1;i<=m;i++)
for (i=1;i<=trcnt;i++)
ans=(anss-ans+md)%md;
cout<%md;
}
BZOJ1030 AC自動機上的DP
description jsoi交給隊員zyx乙個任務,編制乙個稱之為 文字生成器 的電腦軟體 該軟體的使用者是一些低幼人群,他們現在使用的是gw文字生成器v6版。該軟體可以隨機生成一些文章 總是生成一篇長度固定且完全隨機的文章 也就是說,生成的文章中每個位元組都是完全隨機的。如果一篇文章中至少包含...
AC自動機講解
飄過的小牛 ac自動機簡介 首先簡要介紹一下ac自動機 aho corasick automation,該演算法在1975年產生於貝爾實驗室,是著名的多模匹配演算法之一。乙個常見的例子就是給出n個單詞,再給出一段包含m個字元的文章,讓你找出有多少個單詞在文章裡出現過。要搞懂ac自動機,先得有字典樹t...
AC自動機講解
首先,作為作者的我一定知道你已經會了這兩個演算法 kmp與trie樹,如若不會,可以先學習一下。我在這裡宣告一下ac自動機不是自動ac的演算法,其全稱是aho corasick automaton,是一種著名的多模匹配演算法。其實現類似於trie樹與kmp演算法的結合,是將多個模式串放在trie樹上...