hdu2825 Wireless Password
大致题意是:包含下面n个单词中至少m个的长为k个的字符串有几个,n<=25,m<=10,单词的长度也小于时。因为m的范围较小,很容易想到状态压缩dp。
dp[i][j][k]表示长度为i,走到j号节点,状态为k的种数。我是用广搜搜出来的
#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std ;
const int mod = 20090717 ;
int dp[27][111][1025] ;
struct Point
{
int p , step , v ;
} ;
struct Que
{
int tail , head ;
Point q[1000005] ;
void init ()
{
head = 1 , tail = 0 ;
}
bool empty ()
{
return head > tail ;
}
Point front ()
{
return q[head] ;
}
void pop ()
{
head = head + 1 ;
}
void push ( Point x )
{
tail = tail + 1 ;
q[tail] = x ;
}
} Q ;
int vis[27][111][1025] ;
int f[3222] ;
class AC_auto
{
private :
int c[26][111] ;
int id[111] ;
int fail[111] ;
int tot ;
queue<int> Q1 ;
public :
int new_node ()
{
int i ;
for ( i = 0 ; i < 26 ; i ++ ) c[i][tot] = 0 ;
id[tot] = 0 ;
fail[tot] = 0 ;
return tot ++ ;
}
void init ()
{
tot = 0 ; Q.init () ; while ( !Q1.empty () ) Q1.pop () ; new_node () ;
}
void insert ( char *s , int pos )
{
int now = 0 ;
for ( ; *s ; s ++ )
{
int k = *s - 'a' ;
if ( !c[k][now] ) c[k][now] = new_node () ;
now = c[k][now] ;
}
id[now] = 1 << pos ;
}
void get_fail ()
{
int i , j , u = 0 ;
for ( i = 0 ; i < 26 ; i ++ ) if ( c[i][u] ) Q1.push ( c[i][u] ) ;
while ( !Q1.empty () )
{
u = Q1.front () ;
Q1.pop () ;
for ( i = 0 ; i < 26 ; i ++ )
{
if ( !c[i][u] )
{
c[i][u] = c[i][fail[u]] ;
continue ;
}
int e = c[i][u] ;
j = fail[u] ;
while ( j && !c[i][j] ) j = fail[j] ;
fail[e] = c[i][j] ;
Q1.push ( e ) ;
id[e] |= id[fail[e]] ;
}
}
}
void bfs ( Point u , int n , int m )
{
int i , j ;
Point e ;
Q.push ( u ) ;
while ( !Q.empty () )
{
u = Q.front () ;
Q.pop () ;
vis[u.step][u.v][u.p] = 0 ;
if ( u.step == n ) return ;
e.step = u.step + 1 ;
for ( i = 0 ; i < 26 ; i ++ )
{
int k = c[i][u.v] ;
e.v = k ;
if ( !id[k] ) e.p = u.p ;
else e.p = u.p | id[k] ;
dp[e.step][k][e.p] += dp[u.step][u.v][u.p] ;
if ( dp[e.step][k][e.p] >= mod ) dp[e.step][k][e.p] -= mod ;
if ( !vis[e.step][k][e.p] )
{
Q.push ( e ) ;
vis[e.step][k][e.p] = 1 ;
}
}
}
}
int work ( int n , int m , int l )
{
int i , j , k , t ;
int N = 1 << ( m ) ;
for ( j = 0 ; j < N ; j ++ )
for ( i = 0 ; i < tot ; i ++ )
for ( k = 0 ; k <= n ; k ++ )
dp[k][i][j] = vis[k][i][j] = 0 ;
dp[0][0][0] = vis[0][0][0] = 1 ;
Point u ;
u.step = 0 , u.p = 0 , u.v = 0 ;
bfs ( u , n , m ) ;
int ret = 0 ;
for ( i = 0 ; i < N ; i ++ )
{
if ( f[i] < l ) continue ;
for ( j = 0 ; j < tot ; j ++ )
{
ret += dp[n][j][i] ;
if ( ret >= mod ) ret -= mod ;
}
}
return ret ;
}
} ac ;
int main ()
{
int i , j , n , m , l ;
char s[15] ;
for ( i = 0 ; i < ( 1 << 10 ) ; i ++ )
{
n = 0 ;
for ( j = 0 ; j < 10 ; j ++ ) if ( i & ( 1 << j ) ) n ++ ;
f[i] = n ;
}
while ( scanf ( "%d%d%d" , &n , &m , &l ) != EOF )
{
if ( n == 0 && m == 0 && l == 0 ) break ;
ac.init () ;
for ( i = 0 ; i < m ; i ++ )
{
scanf ( "%s" , s ) ;
ac.insert ( s , i ) ;
}
ac.get_fail () ;
printf ( "%d\n" , ac.work ( n , m , l ) ) ;
}
return 0 ;
}