• BZOJ5336:[TJOI2018]游园会——题解


    https://www.lydsy.com/JudgeOnline/problem.php?id=5336

    https://www.luogu.org/problemnew/show/P4590

    小豆参加了NOI的游园会,会场上每完成一个项目就会获得一个奖章,奖章  只会是N, O, I的字样。在会场上他收集到了K个奖章组成的串。
    兑奖规则是奖章串和兑奖串的最长公共子序列长度为小豆最后奖励的等级。
    现在已知兑奖串长度为N,并且在兑奖串上不会出现连续三个奖章为NOI,即奖章中不会出现子串NOI。
    现在小豆想知道各个奖励等级会对应多少个不同的合法兑奖串。

    BZOJ3864 & HDU4899:Hero meet devil大致一样,至于那个多出来的限制想怎么做就怎么做(包括我自己曾想过一个枚举的算法)。

    一个很妙的做法是多记录当前的dp状态的末尾已经到达了"NOI"状态的第几位,然后转移即可。

    #include<cmath>
    #include<queue>
    #include<vector>
    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int p=1e9+7;
    const int N=15;
    const int M=1010;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    int s[N+4];
    int m,n,ans[N+4],f[2][1<<N][3],last[1<<N],trans[1<<N][3],mp[3][3];
    inline void readstring(){
        int cnt=0;char ch=0;
        while(ch<'A'||ch>'Z')ch=getchar();
        while(ch>='A'&&ch<='Z'){
        if(ch=='N')s[++cnt]=0;if(ch=='O')s[++cnt]=1;
        if(ch=='I')s[++cnt]=2;
        ch=getchar();
        }
    }
    void init(){
        static int d[N+4],g[N+4];
        for(int i=0;i< 1<<n;i++){
        if(i)last[i]=last[i^(i&-i)]+1;
        for(int j=0;j<n;j++)d[j+1]=d[j]+(bool)(i&(1<<j));
        for(int k=0;k<3;k++){
            for(int j=1;j<=n;j++){
            g[j]=max(g[j-1],d[j]);
            if(s[j]==k)g[j]=max(g[j],d[j-1]+1);
            }
            trans[i][k]=0;
            for(int j=0;j<n;j++)
            if(g[j+1]-g[j])trans[i][k]|=1<<j;
        }
        }
    }
    int main(){
        m=read(),n=read();
        readstring();
        init();
        f[0][0][0]=1;int now=1;
        mp[0][0]=1;mp[0][1]=0;mp[0][2]=0;mp[1][0]=1;
        mp[1][1]=2;mp[1][2]=0;mp[2][0]=1;mp[2][1]=0;
        for(int i=1;i<=m;i++){
        memset(f[now],0,sizeof(f[now]));
        for(int j=0;j< 1<<n;j++){
            for(int l=0;l<3;l++){
            for(int k=0;k<3;k++){
                if(k==2&&l==2)continue;
                (f[now][trans[j][k]][mp[l][k]]+=f[now^1][j][l])%=p;
            }
            }
        }
        now^=1;
        }
        for(int i=0;i< 1<<n;i++)
        for(int j=0;j<3;j++)
            (ans[last[i]]+=f[now^1][i][j])%=p;
        for(int i=0;i<=n;i++)printf("%d
    ",(ans[i]+p)%p);
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

    +本文作者:luyouqi233。               +

    +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    You don't have permission to access / on this server.
    WampServer修改端口及菜单Localhost
    如何手机访问电脑服务器上的网页?
    Zed Shaw:程序员的常见健康问题
    js中匿名函数的N种写法
    HDU 1561 树形DP背包问题
    COJ 1156 Switching bulbs
    POJ 2891 Strange Way to Express Integers
    FZU 1402 猪的安家 中国剩余定理
    HDU 1573 解同余模线性方程组
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/9092038.html
Copyright © 2020-2023  润新知