• HDU2825 Wireless Password [AC自动机+压缩DP]


      给出M个单词,问长度为N的包含不少于K个单词的字符串一共有多少个。到目前为止做的自动机的题目好像都是差不多样子。。都是包含不包含单词之类的。。

      这题用d[i][j][k]表示第i步走到字符j包含了单词集合k,因为一共只有10个单词,可以用二进制压缩状态表示这个集合。注意在建立trie图时要合并节点和它的fail节点的状态,一开始没想到这个WA了一次。状态转移方程为

      

      不加优化的代码交上去时间接近TLE。。。于是改成了滚动数组,并用for循环清0,还是要跑360ms左右。这相对于1s的时限还是很慢的。。。于是点了下Statistic,发现大家都是跑了好几百ms。。。。

    #include <stdio.h>
    #include <string.h>
    #define MAXN 105
    #define ALP 26
    #define MOD 20090717
    
    int n,m,k;
    char s[11];
    int next[MAXN][ALP],fail[MAXN],flag[MAXN],pos;
    int newnode(){
        for(int i=0;i<ALP;i++)next[pos][i]=0;
        fail[pos]=flag[pos]=0;
        return pos++;
    }
    void insert(char *s,int id){
        int p=0;
        for(int i=0;s[i];i++){
            int k=s[i]-'a',&x=next[p][k];
            p=x?x:x=newnode();
        }
        flag[p]=1<<(id-1);
    }
    int q[MAXN],front,rear;
    void makenext(){
        q[front=rear=0]=0,rear++;
        while(front<rear){
            int u=q[front++];
            for(int i=0;i<ALP;i++){
                int v=next[u][i];
                if(v==0)next[u][i]=next[fail[u]][i];
                else q[rear++]=v;
                if(u&&v){
                    fail[v]=next[fail[u]][i];
                    //这里注意合并状态
                    flag[v]|=flag[fail[v]];
                }
            }
        }
    }
    int d[2][MAXN][MAXN*10];
    //估计是数据比较多,直接用memset比较慢
    void cleard(int x,int f){
        #define FOR(i,n) for(int i=0;i<n;i++)
        FOR(i,pos)FOR(j,f)d[x][i][j]=0;
    }
    int dp(){
        int full=(1<<m),cur=0;
        cleard(0,full);
        d[0][0][0]=1;
        for(int i=0;i<n;i++){
            cur^=1;
            cleard(cur,full);
            for(int u=0;u<pos;u++){
                for(int s=0;s<full;s++){
                    //如果这个状态还没有到达过
                    if(d[cur^1][u][s]==0)continue;
                    //用这个状态跟新它的后继节点
                    for(int k=0;k<ALP;k++){
                        int v=next[u][k],&x=d[cur][v][flag[v]|s];
                        x+=d[cur^1][u][s];
                        if(x>=MOD)x%=MOD;
                    }
                }
            }
        }
        //统计第n步走过>=k个单词的状态的总数
        int ans=0;
        for(int s=0;s<full;s++){
            int bit=0;
            for(int i=s;i;bit++,i-=(i&-i));
            if(bit<k)continue;
            for(int i=0;i<pos;i++){
                ans+=d[cur][i][s];
                if(ans>=MOD)ans%=MOD;
            }
        }
        return ans;
    }
    int main(){
        //freopen("test.in","r",stdin);
        while(scanf("%d%d%d",&n,&m,&k),n||m||k){
            pos=0;newnode();
            for(int i=1;i<=m;i++){
                scanf("%s",s);
                insert(s,i);
            }
            makenext();
            int ans=dp();
            printf("%d\n",ans);
        }
        return 0;
    }

      

  • 相关阅读:
    Edit Distance编辑距离(NM tag)- sam/bam格式解读进阶
    《开讲啦》 20160910 颜宁:女科学家去哪儿了?
    pysam
    Python项目实战
    最小二乘估计法
    最大似然估计(Maximum Likelihood,ML)
    HMM隐马尔科夫模型
    贝叶斯推断|朴素贝叶斯分类|贝叶斯定理
    解决“tar:Exiting with failure status due to previous errors”【转】
    df -h执行卡住不动问题解决【转】
  • 原文地址:https://www.cnblogs.com/swm8023/p/2626535.html
Copyright © 2020-2023  润新知