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;
}
原文地址:https://www.cnblogs.com/wulangzhou/p/3016746.html