HDU - 2825(AC自动机+状态压缩DP(需要优化))

求一个串至少包含k个给定的串的方案数(k个串可相互覆盖-所以只能用AC自动机了)

状态压缩使每个串唯一(1<<i第i个串),防止重复加!(WA)

#include<cstdlib>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
#include<list>
#include<queue>
#include<stack>
#include<vector>
#define tree int o,int l,int r
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define lo o<<1
#define ro o<<1|1
#define pb push_back
#define mp make_pair
#define inf 0x7fffffff
#define eps 1e-7
#define N 105
#define M 26
#define mod 20090717
using namespace std;
int m,n,T,t,k;
int ch[N][M];
int v[N];
int f[N],last[N],num;
int d[N][M][1<<10],ans,ep[M];
void clear()//Trie树初始化
{
    num=1;
    ans=0;
    memset(d,-1,sizeof(d));
    memset(ch[0],0,sizeof(ch[0]));
    memset(v,0,sizeof(v));
    memset(last,0,sizeof(last));
}
int idx(char c)
{
    return c-'a';
}
void insert(char str[],int val)//建Trie树
{
    int len=strlen(str);
    int u=0;
    for (int i=0; i<len; ++i )
    {
        int c=idx(str[i]);
        if(!ch[u][c])//保存的是结点坐标
        {
            memset(ch[num],0,sizeof(ch[num]));
            ch[u][c]=num++;//
        }
        u=ch[u][c];
    }
    v[u]+=(1<<val);//唯一标记一个字符串(+=)
}
void getac()
{
    queue<int> q;//保存的节点下标
    f[0]=0;
    for (int c=0; c<M; ++c )
    {
        int u=ch[0][c];
        if(u)//不需要优化的else
        {
            q.push(u);
            f[u]=0;
            last[u]=v[u];//WA
        }
    }
    while(!q.empty())
    {
        int r=q.front();
        q.pop();
        for (int c=0; c<M; ++c )//注意:c表示节点值,不是结点位置
        {
            int u=ch[r][c];
            if(u)
            {
                q.push(u);
                int s=f[r];
                f[u]=ch[s][c];
                last[u]=(v[u]+last[f[u]]);
            }
            else //重要优化
                ch[r][c]=ch[f[r]][c];
        }
    }
}
char str[20];
int bit(int x)
{
    return x==0?0:(bit(x>>1)+(x&1));
}
int dp(int u,int sub,int num)
{
    if(sub==n)
        return bit(num)>=k;
    int &ans=d[u][sub][num];
    if(ans!=-1)return ans;
    if(bit(num)>=k)//优化!!否则TLE(dp时也是需要优化的!)
    {
        ans=ep[n-sub];return ans;
    }
    ans=0;
    for(int i=0;i<26;i++)
    {
        int c=ch[u][i];
        ans+=dp(c,sub+1,num+(last[c]^(last[c]&num)));
        ans%=mod;
    }
    return ans;
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("ex.in","r",stdin);
#endif
    ep[0]=1;
    for(int i=1;i<=25;i++)
    ep[i]=(ep[i-1]*26)%mod;
    while(scanf("%d%d%d%*c",&n,&m,&k)==3)
    {
        if(!n&&!m&&!k)return 0;
        clear();
        int i=0;
        while(m--)
        {
            scanf("%s",str);
            insert(str,i++);
        }
        getac();
        printf("%d\n",dp(0,0,0));
    }
    return 0;
}
View Code

 

posted @ 2013-10-17 20:04  baoff  阅读(276)  评论(0编辑  收藏  举报