Description
Liyuan lives in a old apartment. One day, he suddenly found that there was a wireless network in the building. Liyuan did not know the password of the network, but he got some important information from his neighbor. He knew the password consists only of lowercase letters 'a'-'z', and he knew the length of the password. Furthermore, he got a magic word set, and his neighbor told him that the password included at least k words of the magic word set (the k words in the password possibly overlapping).Input
There will be several data sets. Each data set will begin with a line with three integers n m k. n is the length of the password (1<=n<=25), m is the number of the words in the magic word set(0<=m<=10), and the number k denotes that the password included at least k words of the magic set. This is followed by m lines, each containing a word of the magic set, each word consists of between 1 and 10 lowercase letters 'a'-'z'. End of input will be marked by a line with n=0 m=0 k=0, which should not be processed.Output
For each test case, please output the number of possible passwords MOD 20090717.Sample Input
10 2 2 hello world 4 1 1 icpc 10 0 0 0 0 0
Sample Output
2 1 14195065
題意:讓你構造一個長度為n的字符串,使得至少包含共m個的集合裡的k個,求個數。
思路:AC自動機構造,需要用到DP的思想,設dp[i][j][k]表示長度為i到達自動機狀態為j的時候且狀態k時的個數。我們需要用一個來表示狀態j包含的字符串的個數,也就是走到字符串末尾的個數,二進制表示。然後還要注意一點的是:我們在構造自動機的時候有fail指針的轉移,所以狀態j也需要結合它失配時候的狀態。
#include
#include
#include
#include
#include
using namespace std;
const int mod = 20090717;
int n, m, k;
int dp[30][250][1<<10];
int num[5000];
struct Trie {
int nxt[110][26], fail[110], end[110];
int root, sz;
int newNode() {
for (int i = 0; i < 26; i++)
nxt[sz][i] = -1;
end[sz++] = 0;
return sz - 1;
}
void init() {
sz = 0;
root = newNode();
}
void insert(char buf[], int id) {
int now = root;
for (int i = 0; buf[i]; i++) {
if (nxt[now][buf[i]-'a'] == -1)
nxt[now][buf[i]-'a'] = newNode();
now = nxt[now][buf[i]-'a'];
}
end[now] |= (1< q;
fail[root] = root;
for (int i = 0; i < 26; i++) {
if (nxt[root][i] == -1)
nxt[root][i] = root;
else {
fail[nxt[root][i]] = root;
q.push(nxt[root][i]);
}
}
while (!q.empty()) {
int now = q.front();
q.pop();
end[now] |= end[fail[now]];
for (int i = 0; i < 26; i++) {
if (nxt[now][i] == -1)
nxt[now][i] = nxt[fail[now]][i];
else {
fail[nxt[now][i]] = nxt[fail[now]][i];
q.push(nxt[now][i]);
}
}
}
}
int solve() {
for (int i = 0; i <= n; i++)
for (int j = 0; j < sz; j++)
for (int k = 0; k < (1< 0) {
for (int x = 0; x < 26; x++) {
int ni = i+1;
int nj = nxt[j][x];
int nk = k | end[nj];
dp[ni][nj][nk] += dp[i][j][k];
dp[ni][nj][nk] %= mod;
}
}
int ans = 0;
for (int p = 0; p < (1<