日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【hdu2825】ac自动机 + 状压dp

發布時間:2025/3/15 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【hdu2825】ac自动机 + 状压dp 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

傳送門

題目大意:

給你一些密碼片段字符串,讓你求長度為n,且至少包含k個不同密碼片段串的字符串的數量。

題解:

因為密碼串不多,可以考慮狀態壓縮

設dp[i][j][sta]表示長為i的字符串匹配到j節點且狀態為sta的數量。

其中sta存儲的是包含的密碼串情況,在構建fail指針時,當前節點要并上fail指針所指的節點。

跑ac自動機,兒子節點從父親節點轉移。

最后取dp[len][...][sta]的和,其中sta滿足二進制中1的數量>=k,

這一點可以像樹狀數組的lowbit那樣快速求出:

inline int count(int x){int ret = 0;while(x){ret++;x -= (x & -x);}return ret; }

code

#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<algorithm> #include<queue> using namespace std; const int N = 20, L = 20, Mod = 20090717; int n, m, k, tot; long long dp[30][110][1100], ans; char s[20]; queue<int> que; struct node{int trans[27];int fail, no;int state;inline void clear(){memset(trans, 0, sizeof trans);fail = state = no = 0;} }trie[1010]; inline int getVal(char st){return st - 'a' + 1; } inline void insert(int num){int len = strlen(s + 1), pos = 1;for(int i = 1; i <= len; i++){int val = getVal(s[i]);if(!trie[pos].trans[val])trie[trie[pos].trans[val] = ++tot].clear();pos = trie[pos].trans[val];}trie[pos].state |= 1 << num; } inline void buildFail(){for(int i = 1; i <= 26; i++) trie[0].trans[i] = 1;que.push(1);while(!que.empty()){int u = que.front(); que.pop();for(int i = 1; i <= 26; i++){int v = trie[u].fail;while(!trie[v].trans[i]) v = trie[v].fail;int w = trie[u].trans[i];v = trie[v].trans[i];if(w){trie[w].fail = v;que.push(w);trie[w].state |= trie[v].state;}else trie[u].trans[i] = v;}} } inline int count(int x){int ret = 0;while(x){ret++;x -= (x & -x);}return ret; } inline void solve(){memset(dp, 0, sizeof dp);int limit = 1 << m;dp[0][1][0] = 1;for(int i = 1; i <= n; i++)for(int j = 1; j <= tot; j++)for(int sta = 0; sta < limit; sta++)if(dp[i - 1][j][sta])for(int l = 1; l <= 26; l++){int u = trie[j].trans[l];dp[i][u][sta | trie[u].state] = (dp[i][u][sta | trie[u].state] + dp[i - 1][j][sta]) % Mod;}for(int i = 1; i <= tot; i++)for(int sta = 0; sta < limit; sta++){if(count(sta) >= k)ans = (ans + dp[n][i][sta]) % Mod;} } int main(){while(scanf("%d%d%d", &n, &m, &k), n + m + k){trie[tot = 1].clear(); ans = 0;for(int i = 1; i <= m; i++){scanf("%s", s + 1);insert(i - 1);}buildFail();solve();cout << ans << endl;} }

轉載于:https://www.cnblogs.com/CzYoL/p/7450429.html

總結

以上是生活随笔為你收集整理的【hdu2825】ac自动机 + 状压dp的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。