JSOI2007 文字生成器(AC自動機)

2022-03-17 01:57:42 字數 1189 閱讀 9144

給定一些模式串,求長度為m的所有文字串的個數,且該文字串至少包括乙個模式串,答案對10007取模

//沒有呼叫get_fail()調了乙個小時我怕不是神仙....

看到一堆字串的匹配問題,首先就可以考慮自動機全家桶了......很容易發現用ac自動機看起來可做

對所有串建ac自動機,然後變成trie圖,乙個文字串只要包括了乙個end標記就說明包括至少乙個串。在圖上這樣的統計問題,容易想到是dp

於是大多數題解到這裡就運用了乙個經典的四字成語

才怪雖然正難則反(所有串-不包含任乙個的串)可做,但是按照正常的思路來說,則反首先要正難,然而它並不難......對於我這個蒟蒻來說很難就此想到反推(個人認為否定正著做會誤導萌新比如本人)

用f[ i ][ j ][0 / 1]表示到了i號點,當前字串長度為j,是否經過過有標記的點,這樣的總方案數,那麼最終的答案就為sigma( f[ 0 ~ ndsum ][ m ][ 1 ] )。

這樣遞推也是相當簡單的,為了保證前一位先被求出來,所以外層迴圈先列舉字串長度j

if(is_end[now])//是終點就沒有0狀態 

else//不是終點

再加入ac自動機模板即可輕鬆切掉()

code:

#include#define n 6100

using namespace std;

const int mod = 10007;

int n,m;

int nxt[n][26],fail[n],is_end[n],ndsum;

int f[n][105][2];//走了j步走到了i點,是否有經過單詞

char s[n];

void ad(char c)

else nxt[u][j]=nxt[fail[u]][j];

} }}void dp()

else//不是終點

}} }

}int main()

get_fail();

dp();

int ans=0;

for(int i=0;i<=ndsum;++i) ans=(ans+f[i][m][1])%mod;

printf("%d\n",ans);

return 0;

}

(當然這道題f的第二維顯然是可以滾掉的2333)

JSOI2007 文字生成器

用ac自動機處理所有了解的單詞 顯然,不能直接算,直接算的話,我們需要大力容斥,複雜度不允許 我們不妨反過來做,我們根據ac自動機處理出所有的不可行解,然後用總數減去即可 計算所有不可行解用dp,f i j 表示處理到字串第i位,在自動機上第j個節點的不可行方案數,直接暴力轉移即可 include ...

JSOI2007 文字生成器

容斥原理,求出所有的情況減去不可讀的情況就是可讀的文字數了a 找不可讀文字的數量類似於病毒那一題趴我覺得 dp轉移的話.用f i j 表示當前在節點j,且串長為i時的情況 include using namespace std const int mod 1e4 7 const int n 2000...

JSOI2007 文字生成器

對於乙個長度為 n 的串 s 有多少可能情況的串 s 使得 s 的子串中至少包含乙個給定的串,給定的串有 m 個 由多模式串匹配想到ac自動機,由計數想到dp 首先建好trie圖,更新所有end標記。記 dp now st flag 表示當前正在匹配第 st 位,已確定的串匹配到了trie圖上的 n...