码迷,mamicode.com
首页 > 其他好文 > 详细

hdu2825 Wireless Password [AC自动机+状压dp]

时间:2015-06-04 11:49:46      阅读:125      评论:0      收藏:0      [点我收藏+]

标签:dp   自动   network   

Problem Description

给你一些字符串,你需要求出长度为n的字符串中,包含至少k个给定串的字符串有多少个。

Input

多组数据,第一行三个整数n表示所求串的长度(1<=n<=25), m 表示给定串的个数(0<=m<=10), 以及k表示至少包含k个给定串. 然后m行描述给定串, 每个串长度不超过10,由小写字母组成.
0 0 0表示输入结束。

Output

每组数据输出结果模20090717.

Sample Input

10 2 2
hello 
world 
4 1 1
icpc 
10 0 0
0 0 0

Sample Output

2
1
14195065

Solution

建立AC自动机然后状压。。
唉AC自动机玩的不6啊。。。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>

using namespace std;

const int MOD = 20090717;

int n, m, k, tot, root;
int nex[105][26], fail[105], ed[105];

void insert(char str[], int id) {
    int len = strlen(str);
    int pos = root;
    for (int i = 0; i < len; i++) {
        int t = str[i] - ‘a‘;
        if (!nex[pos][t])
            nex[pos][t] = ++tot;
        pos = nex[pos][t];
    }
    ed[pos] |= (1 << id);
}

void build() {
    queue<int> q;
    q.push(0);
    while (!q.empty()) {
        int p = q.front();
        q.pop();
        ed[p] |= ed[fail[p]];
        int t;
        for (int i = 0; i < 26; i++) {
            if (!(t = nex[p][i]))
                nex[p][i] = nex[fail[p]][i];
            else {
                fail[t] = p ? nex[fail[p]][i] : 0;
                q.push(t);
            }
        }
    }
}

int num[5030];
int dp[30][105][1 << 10];
int main() {
    for (int i = 0; i < 1 << 10; i++)
        for (int j = 0; j < 10; j++)
            num[i] += ((i >> j) & 1);
    while (~scanf("%d %d %d", &n, & m, &k)) {
        if (!n && !m && !k) break;
        char str[25];
        tot = root = 0;
        memset(ed, 0, sizeof(ed));
        memset(nex, 0, sizeof(nex));
        for (int i = 0; i < m; i++) {
            scanf("%s", str);
            insert(str, i);
        }
        build();
        memset(dp, 0, sizeof(dp));
        dp[0][0][0] = 1;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j <= tot; j++) {
                for (int p = 0; p < 1 << m; p++) {
                    if (!dp[i][j][p]) continue;
                    for (int id = 0; id < 26; id++) {
                        int nj = (p | ed[nex[j][id]]);
                        dp[i + 1][nex[j][id]][nj] += dp[i][j][p];
                        dp[i + 1][nex[j][id]][nj] %= MOD;
                    }
                }
            }
        }
        int ans = 0;
        for (int p = 0; p < 1 << m; p++) {
            if (num[p] < k) continue;
            for (int i = 0; i <= tot; i++) {
                ans += dp[n][i][p];
                ans %= MOD;
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

hdu2825 Wireless Password [AC自动机+状压dp]

标签:dp   自动   network   

原文地址:http://blog.csdn.net/u011265346/article/details/46358027

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!