H - Wireless Password HDU - 2825(AC自动机+状压DP)
2017-07-28 14:01
531 查看
我对DP向来是比较抗拒的,觉得以我的智商太难理解了。近期在刷字符串处理,结果遭遇到了这道题。这个题目真的很有意思,用的还是状态压缩dp, 第一次尝试写状压dp, 发现理解了还是很好写的。
dp[i][j][k]分别表示的是当枚举到第i个字符时, 其当下处于AC自动机的的第j个节点,其包含已知的字符串是用k这个数字的集合表示的(状态压缩在k上)。
所以状态转移方程为 dp[i+1][next[j][t]][k | end1[next[j][t]] ] += dp[i][j][k];
其中i表示枚举到第i个位置, j表示当前所在AC自动机的节点位置, next为AC自动机中的字典树的指指向位置,t为在i+1处出现的字符, end中记录的是当匹配到当下节点时所包含的已知字符串的集合。
代码如下:
b867
/div>
dp[i][j][k]分别表示的是当枚举到第i个字符时, 其当下处于AC自动机的的第j个节点,其包含已知的字符串是用k这个数字的集合表示的(状态压缩在k上)。
所以状态转移方程为 dp[i+1][next[j][t]][k | end1[next[j][t]] ] += dp[i][j][k];
其中i表示枚举到第i个位置, j表示当前所在AC自动机的节点位置, next为AC自动机中的字典树的指指向位置,t为在i+1处出现的字符, end中记录的是当匹配到当下节点时所包含的已知字符串的集合。
代码如下:
#include <iostream> #include <stdio.h> #include <algorithm> #include <cstring> #include <math.h> #include <queue> using namespace std; #define Max_N 110 int n, m, k; struct Trie { int next[Max_N][26], fail[Max_N], end1[Max_N]; int root, L; int newnode() { for (int i = 0; i < 26; i++) next[L][i] = -1; end1[L++] = 0; return L-1; } void init() { L = 0; root = newnode(); } void insert(char buf[], int x) { int len = strlen(buf); int now = root; for (int i = 0; i < len; i++) { if (next[now][buf[i] - 'a'] == -1) next[now][buf[i]-'a'] = newnode(); now = next[now][buf[i] - 'a']; } end1[now] |= 1<<x;//这里表示了把第x个字符转化成状压的形式存在了end1数组中。 } void build() { queue<int> q; fail[root] = root; for (int i = 0; i < 26; i++) if (next[root][i] == -1) next[root][i] = root; else { fail[next[root][i]] = root; q.push(next[root][i]); } while (!q.empty()) { int now = q.front(); q.pop(); end1[now] |= end1[fail[now]];//这里要注意如果当前节点的失配节点也是标记的字符,那么就要求两个标记集合的并集。 for (int i = 0; i < 26; i++) if (next[now][i] == -1) next[now][i] = next[fail[now]][i]; else { fail[next[now][i]] = next[fail[now]][i]; q.push(next[now][i]); } } } int query(char buf[]) { int len = strlen(buf); int now = root; int res = 0; for (int i = 0; i < len; i++) { now = next[now][buf[i] - 'a']; int temp = now; while (temp != root) { res += end1[temp]; end1[temp] = 0; temp = fail[temp]; } } return res; } }; long long int get_num(int x) { int res = 0; for (int i = 0; i <= m; i++) if ((1<<i) & x) res++; return res; } char buf[100]; Trie ac; long long int dp[26][110][1<<10]; #define MON 20090717 int main() { while (~scanf("%d%d%d",&n,&m,&k) && (n||m||k)) { ac.init(); for (int i = 0; i < m; i++) { scanf("%s", buf); ac.insert(buf, i); } ac.build(); memset(dp, 0, sizeof(dp)); dp[0][0][0] = 1;//初始化。 //cout << ac.L <<endl; for (int i = 0; i < n; i ++) for (int j = 0; j < ac.L; j++) { for (int w = 0; w < (1 << m); w++) { if (dp[i][j][w] == 0) continue;//节约时间 for (int t = 0; t < 26; t++) { int next1 = ac.next[j][t]; dp[i+1][next1][w|ac.end1[next1]] += dp[i][j][w]; dp[i+1][next1][w|ac.end1[next1]] %= MON;//我们是从当前节点往下一节点枚举的。 } } } long long int sum = 0; for (int i = 0; i < ac.L; i++) for (int w = 0; w < (1<<m); w++) { if (get_num(w) >= k) sum += dp [i][w]; sum %= MON; } printf("%lld\n", sum); } return 0; }<
b867
/div>
相关文章推荐
- HDU 2825 Wireless Password && AC自动机+状压DP
- HDU 2825(Wireless Password-AC自动机+状压dp)
- HDU-2825 Wireless Password(AC自动机+状压DP)
- HDU 2825 Wireless Password(AC自动机+状压DP)
- hdu 2825 Wireless Password(AC自动机+状压DP)
- Wireless Password - HDU 2825(ac自动机+状态压缩)
- HDU 2825 AC自动机+状压DP
- hdu 2825 aC自动机+状压dp
- hdu 2825 AC自动机+状压dp
- hdu_2825_Wireless Password(AC自动机+状压DP)
- HDU 2825 Wireless Password(AC自动机+状压DP)
- [AC自动机+状压dp] hdu 2825 Wireless Password
- hdu2825 Wireless Password [AC自动机+状压dp]
- hdu 2825 Wireless Password (ac自动机+状压dp)
- hdu 2825 Wireless Password(AC自动机+状压DP)
- HDU 2825 Wireless Password(AC自动机+状态压缩DP)
- AC自动机+状压dp hdu2825 Wireless Password
- HDU 2825 Wireless Password(AC自动机+状态压缩DP)
- HDU 2825 Wireless Password(AC自动机+状态压缩DP)
- HDU 2825 Wireless Password(AC自动机+DP)