BZOJ 1559 密碼 AC自動機 狀壓DP

2021-08-29 16:30:09 字數 2224 閱讀 3716

求有多少個長度為l,且包含n個串的字串,答案小於等於42時輸出方案。(n<=10,l<=25,|s|<=10)

常規的ac自動機上的壯壓dp,通過fail去掉那些被包含的字串即可。

d p[

i][j

][s]

:dp[i][j][s]:

dp[i][

j][s

]:走了i

ii步,當前在點j

jj,已經走過的串的二進位制為s

ss的方案數。

d p[

i+1]

[ch[

j][c

]][s

∣ed[

ch[j

][c]

]]+=

dp[i

][j]

[s

]dp[i+1][ch[j][c]][s|ed[ch[j][c]]]+=dp[i][j][s]

dp[i+1

][ch

[j][

c]][

s∣ed

[ch[

j][c

]]]+

=dp[

i][j

][s]

a ns

+=dp

[l][

i][s

(全集)

]ans+=dp[l][i][s(全集)]

ans+=d

p[l]

[i][

s(全集

)]由於答案小於等於42才輸出方案,這個時候所有n個字串都是緊密相連的,可以從終止狀態開始搜尋,也可以n!列舉每個字串的相對位置,由於已經去掉了包含關係,所以相鄰的字串之間盡量多的重疊即可。

#include

#include

#include

#include

#include

#include

using namespace std;

#define maxn 105

#define maxm 1024

#define ll long long

ll dp[30]

[maxn]

[maxm]

,sum;

int ch[maxn][26

],tot,cnt,s,fail[maxn]

,ed[maxn]

;char s[15]

,mem[maxn]

,a[30];

vectorans;

void

insert()

nw=ch[nw]

[c];

} ed[nw]=1

;}queue<

int>q;

void

build()

}for

(int i=

0;i<=tot;i++

) ed[fail[i]]=

0;for(

int i=

0;i<=tot;i++)if

(ed[i]

) ed[i]=1

dfs(

int len,

int pos,

int sta)

int c=mem[pos]

-'a'

;for

(int i=

0;i<=tot;i++)if

(dp[len-1]

[i][sta]

&&ch[i]

[c]==pos)

dfs(len-

1,i,sta);if

(ed[pos])}

intmain()

build()

; s=

1

[0][

0]=1

;for

(int i=

0;i)for

(int j=

0;j<=tot;j++

)for

(int s=

0;s(dp[i]

[j][s]

)for

(int i=

0;i<=tot;i++

) sum+

=dp[l]

[i][s-1]

;printf

("%lld\n"

,sum);if

(sum<=42)

}

AC自動機 玄武密碼

題目鏈結 題意 對於每一段文字,其字首在母串上的最大匹配長度是多少呢 參考別人的題解 我們只需要先建立所有密碼的trie樹 再以母串為主串跑乙個ac自動機 不過其中還是有一些需要改動的地方 原本字典樹中用來記錄某個節點是不是字串結尾的陣列不需要,直接刪去 我們需要另乙個陣列來標記哪些點被匹配 跑完a...

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...