JSOI2007 文字生成器

2022-03-17 01:57:46 字數 1049 閱讀 5127

對於乙個長度為 \(n\) 的串 \(s\) ,有多少可能情況的串 \(s\) 使得 \(s\) 的子串中至少包含乙個給定的串,給定的串有 \(m\) 個

由多模式串匹配想到ac自動機,由計數想到dp

首先建好trie圖,更新所有end標記。記 \(dp[now][st][flag]\) 表示當前正在匹配第 \(st\) 位,已確定的串匹配到了trie圖上的 \(now\) 號節點,\(flag\) 表示是否已經出現過給定的模式串。總共有 \((\sum_^ |s_i|)\times n \times 2\) 種狀態,顯然要記憶化搜尋。對於每個狀態列舉下一位所有可能的 \(26\) 位字元,並在trie圖上進行節點轉移,flag或上end標記,最後累加答案。當 \(st=n+1\) 即已經匹配完成時,返回值為flag的狀態(顯然若有給定字串則貢獻 \(1\) 的答案)。最終的結果為初始狀態 \(dp[0][1][false]\)

#include#include#includeusing namespace std;

#define mod 10007

#define n 107

templateinline void read(t &x)

while(c>='0'&&c<='9')

x*=flag;

}struct triego[n*100];

int cnt=0,n,m,f[n*100][n][2];

char s[n];

queueq;

inline void insert()

go[now].end=1;

}inline void get_fail()else go[u].vis[i]=go[go[u].fail].vis[i];

}}int dfs(int now,int st,bool flag)

return f[now][st][flag]=ret;

}int main()

get_fail();

printf("%d",dfs(0,1,false));}/*

2 2ab

ba*/

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 文字生成器

ac 機上的計數 dp 啊 並沒有想到反著求出不合法的串的個數,直接正面硬上 設 dp i j 0 1 表示匹配出的長度為 i 在 ac 機上位置為 j 沒有 有匹配到乙個完整串的方案數 由於這個的長度是滿足子結構的,可以直接 dp 求解 注意結束標記會影響到所有能通過跳 fail 到達它的點,所以...