zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    汉字转拼音的Java类库——JPinyin
    更改MySQL数据库的编码为utf8mb4
    mysql 添加列,修改列,删除列
    mysql解决datetime与timestamp精确到毫秒的问题
    mysql之数据库备份与恢复
    linux常用命令集锦
    如何更改linux文件目录拥有者及用户组
    linux 查找文件命令
    关于servlet中重定向、转发的地址问题
    jQuery的validation插件(验证表单插件)
  • 原文地址:https://www.cnblogs.com/algorithms/p/2667728.html
Copyright © 2011-2022 走看看