給定一些模式串,求長度為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...