HDOJ 2825 Wireless Password (AC自动机+DP)

题意:给m个字符串,求长为n且至少包含k个上述字符串的字符串有多少个。

数据范围:(1<=n<=25),(0<=m<=10)

分析:用dp[i][cur][s]表示走i步后,到达结点cur,包含的字符串压缩为状态s(第x位为1表示包含第x个字符串)的字符串有多少个。

TLE:当dp[i-1][pre][s]=0时,直接continue,不用进入下一层循环,经此优化后就AC了。

View Code
#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;
#define NODE 101
#define MOD 20090717

int n,m,cnt;
int next[NODE][26],fail[NODE],flag[NODE],node;
int dp[26][NODE][1<<10];

int newnode()
{
    fail[node]=flag[node]=0;
    memset(next[node],0,sizeof(next[0]));
    return node++;
}
void insert(char *s,int id)
{
    int i,k,cur;
    for(i=cur=0;s[i];i++)
    {
        k=s[i]-'a';
        if(!next[cur][k])   next[cur][k]=newnode();
        cur=next[cur][k];
    }
    flag[cur] |=(1<<id);
}
void makenext()
{
    int u,v;
    queue<int>q;

    q.push(0);
    while(!q.empty())
    {
        u=q.front(),q.pop();
        for(int k=0;k<26;k++)
        {
            v=next[u][k];
            if(v)   q.push(v);
            else    next[u][k]=next[fail[u]][k];
            if(u&&v)
            {
                fail[v]=next[fail[u]][k];
                flag[v] |=flag[fail[v]];
            }
        }
    }
}
int cal(int s)
{
    int ret=0;
    while(s)
    {
        ret+=s&1;
        s>>=1;
    }
    return ret;
}
void DP()
{
    for(int i=0;i<=n;i++)
    {
        for(int j=0;j<node;j++)
            memset(dp[i][j],0,sizeof(dp[0][0][0])*(1<<m));
    }
    dp[0][0][0]=1;

    for(int i=1;i<=n;i++)
    {
        for(int pre=0;pre<node;pre++)
        {
            for(int s=0;s<(1<<m);s++)
            {
                if(dp[i-1][pre][s]==0)  continue;
                for(int k=0;k<26;k++)
                {
                    int cur=next[pre][k];
                    int ns=s | flag[cur];
                    dp[i][cur][ns]+=dp[i-1][pre][s];
                    dp[i][cur][ns]%=MOD;
                }
            }
        }
    }
    int ans=0;
    for(int cur=0;cur<node;cur++)
    {
        for(int s=0;s<(1<<m);s++)
        {
            if(cal(s)>=cnt)
            {
                ans+=dp[n][cur][s];
                ans%=MOD;
            }
        }
    }
    printf("%d\n",ans);
}
int main()
{
    char s[11];
    while(scanf("%d%d%d",&n,&m,&cnt))
    {
        if(!n&&!m&&!cnt)    break;
        node=0,newnode();
        for(int i=0;i<m;i++)
        {
            scanf("%s",s);
            insert(s,i);
        }
        makenext();
        DP();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/algorithms/p/2667728.html