http://acm.hdu.edu.cn/showproblem.php?pid=2825
题意:
给你M个最长长度为10的字符串,问有多少个仅由小写字母构成的,至少有
K个给定字符串的字符串。
思路:
AC自动机+dp。dp( i , j , k)表示长度为i的字符串,在trie中的第j个结点时,含
有的字符串的信息为k时候的种数。dp(i ,j , k ) = sum{ dp( i-1 ,j' ,k' )} ;这样的状态
转移方程的复杂度为:O(N*kind*2^M*node_num),其中kind为字符的取值域,
node_num为trie树中一共有多少个结点。
代码:
#include<stdio.h>
#include<string.h>
#include<queue>
const int Mod = 20090717 ;
int N ,M, K ;
struct Node{
int fail ;
int end ;
int next[26] ;
void init(){
fail = -1 ;
end = 0 ;
memset(next, -1, sizeof(next));
}
}p[110] ;
int Root, cnt ;
void build(char *ch,int num){
int loc , idx ,len = strlen(ch);
loc = Root ;
for(int i=0;i<len;i++){
idx = ch[i] - 'a' ;
if( p[loc].next[idx] == -1){
++cnt ;
p[cnt].init() ;
p[loc].next[idx] = cnt ;
}
loc = p[loc].next[idx] ;
}
p[loc].end |= (1<<(num-1)) ;
}
void build_ac(){
int loc = Root ;
p[loc].fail = -1 ;
std::queue<int > que ;
while(!que.empty()) que.pop() ;
que.push(loc) ;
while(!que.empty()){
int u = que.front() ; que.pop() ;
for(int i=0;i<26;i++){
int v = p[u].next[i] ;
if(v == -1){
if(u == Root)
p[u].next[i] = Root ;
else
p[u].next[i] = p[ p[u].fail ].next[i] ;
}
else{
int temp = p[u].fail ;
if(u == Root)
p[v].fail = Root ;
else{
p[v].fail = p[temp].next[i] ;
p[v].end |= p[p[temp].next[i]].end ;
}
que.push(v) ;
}
}
}
}
int dp[30][110][1030] ;
int map[1050] ;
void DP(){
memset(dp , 0 ,sizeof(dp));
dp[0][0][0] = 1 ;
int MA = (1<<M) ;
for(int j=0;j<MA;j++){
map[j] = 0 ;
for(int i=1;i<=M;i++)
if( j&(1<<(i-1)) ) map[j] ++ ;
}
for(int i=1;i<=N;i++){
for(int j=0;j<=cnt;j++){
for(int k=0;k<MA;k++){
if( dp[i-1][j][k] == 0 ) continue ;
if( ( k & p[j].end ) != p[j].end ) continue ;
for(int c=0;c<26;c++){
int v = p[j].next[c] ;
int kk = k | p[v].end ;
dp[i][v][kk] += dp[i-1][j][k] ;
if( dp[i][v][kk] >= Mod) dp[i][v][kk] %= Mod ;
}
}
}
}
int ans = 0 ;
for(int j=0;j<=cnt;j++){
for(int k=0;k<MA;k++){
if(map[k] >= K)
ans = ( ans + dp[N][j][k] ) % Mod ;
}
}
printf("%d\n",ans);
}
int main(){
char ch[20] ;
Root = 0 ;
while(scanf("%d%d%d",&N,&M,&K) == 3){
if(0==N && M==0 && K==0) break ;
p[Root].init() ; cnt = 0 ;
for(int i=1;i<=M;i++){
scanf("%s",ch);
build(ch,i);
}
build_ac() ;
DP() ;
}
return 0 ;
}