HDU 2825 Wireless Password
Wireless Password
http://acm.hdu.edu.cn/showproblem.php?pid=2825
题意:
求有多少长度为n的串,包含给定的串的至少k个串。
分析:
AC自动机+dp,首先对给定的m个串建立AC自动机,然后状压dp,dp[i][j][s]表示当前的串的长度是i,在AC自动机的节点j上,状态(已经满足的串)是s的方案数。
注意:1、将每个点所满足的所有串,都或起来,这个点可以把这些子串都包含进去。2、代码40行要有,在AC自动机上一旦不匹配了,就可以走回去了。
代码:
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<iostream> 5 #include<cmath> 6 #include<cctype> 7 #include<set> 8 #include<queue> 9 #include<vector> 10 #include<map> 11 using namespace std; 12 typedef long long LL; 13 14 inline int read() { 15 int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; 16 for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; 17 } 18 19 const int mod = 20090717; 20 21 int dp[26][150][1200], ch[150][27], sta[150], q[150], fail[150], Index; 22 char s[150]; 23 24 void Insert(char *s,int id) { 25 int n = strlen(s), u = 0; 26 for (int i = 0; i < n; ++i) { 27 int c = s[i] - 'a'; 28 if (!ch[u][c]) ch[u][c] = ++Index; 29 u = ch[u][c]; 30 } 31 sta[u] |= (1 << id); 32 } 33 void bfs() { 34 int L = 1, R = 0; 35 for (int i = 0; i < 26; ++i) if (ch[0][i]) q[++R] = ch[0][i]; // q[++R] = i!!! 36 while (L <= R) { 37 int u = q[L ++]; 38 for (int c = 0; c < 26; ++c) { 39 int v = ch[u][c]; 40 if (!v) { ch[u][c] = ch[fail[u]][c]; continue; } 41 int p = fail[u]; while (p && !ch[p][c]) p = fail[p]; 42 fail[v] = ch[p][c]; 43 q[++R] = v; 44 sta[v] |= sta[fail[v]]; 45 } 46 } 47 } 48 inline void add(int &x,int y) { x += y; if (x >= mod) x -= mod; } 49 inline void sub(int &x,int y) { x -= y; x < 0 && (x += mod); } 50 void solve(int n,int m,int k) { 51 dp[0][0][0] = 1; 52 int All = (1 << m) - 1; 53 for (int i = 0; i < n; ++i) 54 for (int j = 0; j <= Index; ++j) 55 for (int s = 0; s <= All; ++s) { 56 if (dp[i][j][s] <= 0) continue; 57 for (int c = 0; c < 26; ++c) { 58 int nv = ch[j][c], ns = s | sta[nv]; 59 add(dp[i + 1][nv][ns], dp[i][j][s]); 60 } 61 } 62 int ans = 0; 63 for (int s = 0; s <= All; ++s) { 64 int cnt = 0; 65 for (int i = 0; i < m; ++i) if ((s >> i) & 1) cnt ++; 66 if (cnt >= k) { 67 for (int i = 0; i <= Index; ++i) add(ans, dp[n][i][s]); 68 } 69 } 70 printf("%d\n",ans); 71 } 72 void init() { 73 Index = 0; 74 memset(ch, 0, sizeof(ch)); 75 memset(sta, 0, sizeof(sta)); 76 memset(dp, 0, sizeof(dp)); 77 memset(fail, 0, sizeof(fail)); 78 } 79 int main() { 80 int n, m, k; 81 while (~scanf("%d%d%d", &n, &m, &k)) { 82 if (!n && !m && !k) break; 83 init(); 84 for (int i = 1; i <= m; ++i) { 85 scanf("%s", s); Insert(s, i - 1); 86 } 87 bfs(); 88 solve(n, m, k); 89 } 90 return 0; 91 }