HDU 2825 位压缩
题意,,,给你 M 个字符去组成密码,密码的长度规定为 N,所组成的密码要求至少 含有 M 个字符里面的 K 个,字符可能包含,不能重复计算;
这个 有点难度;因为 M 很小,所以,可以用二进制来做,当然 内存可能会爆,如果不注意好的话; 上题是要不包含字符,而这题是要求包含字符,那么对应的每一个状态是不是又多了一维变量,每个状态包含了多少个字符,从 1~k --》
#include<iostream> #include<stdio.h> #include<cstring> #include<algorithm> #define mod 20090717 using namespace std; struct date { date *next[26],*fail; int in,cnt; }tree[1221],*que[1221],*root; int N,M,P,tail,head,total; char dir[20][20]; date *creat_node( ) { for( int i = 0; i < 26; i++ ) tree[total].next[i] = NULL; tree[total].fail = NULL; tree[total].in = total; tree[total].cnt = 0; return &tree[total++]; } void inint( ) { tail = head = total = 0; root = creat_node(); root->fail = root; } void insert( char *word,int i ) { date *temp = root; while( *word ) { int k = *word - 'a'; if( temp->next[k] == NULL ) temp->next[k] = creat_node(); temp = temp->next[k]; word++; } temp->cnt |= (1<<i); } void build_AC( ) { que[tail++] = root; while( tail > head ) { date *temp = que[head++]; for( int i = 0; i < 26; i++ ) if( temp->next[i] ) { if( temp == root ) temp->next[i]->fail = root; else temp->next[i]->fail = temp->fail->next[i]; temp->next[i]->cnt = temp->next[i]->cnt|temp->fail->next[i]->cnt|temp->cnt; que[tail++] = temp->next[i]; } else { if( temp == root ) temp->next[i] = root; else temp->next[i] = temp->fail->next[i]; } } } int map[1500]; void work( ) { for( int i = 0; i <= 1500; i++ ) map[i] = map[i>>1] + (i&1); } int dp[27][121][1500]; void DP( ) { int i,j,k,l,pos,res; pos = (1<<M ); for (i = 0; i <= N; ++i) for (j = 0; j < total; ++j) for (k = 0; k < (1<<M); ++k) dp[i][j][k] = 0; dp[0][0][0] = 1; for( i = 1; i <= N; i++ ) for( j = 0; j <total; j++ ) for( k = 0; k < pos; k++ ) { if( dp[i-1][j][k] == 0 ) continue; int a = dp[i-1][j][k]; for( l = 0; l < 26; l++ ) { int b = tree[j].next[l]->in; int c = tree[j].next[l]->cnt; dp[i][b][k|c] = ( a + dp[i][b][k|c] )%mod; } } res = 0; for( i = 0; i < total; i++ ) for( j = 0; j < pos; j++ ) if( map[j] >= P ) res = ( res + dp[N][i][j] )%mod; printf("%d\n",res); } int main( ) { work(); while( scanf("%d%d%d",&N,&M,&P) != EOF ) { if( N+M+P == 0 )break; inint(); for( int i = 0; i < M; i++ ) scanf("%s",&dir[i]),insert( dir[i],i ); build_AC( ); DP( ); } return 0; }