BZOJ 5336: [TJOI2018]party Dp套Dp

title

\(~\)
BZOJ 5336
LUOGU 4590
Description

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

Input

第一行两个数,N,K分别代表兑奖串的长度,小豆收集的奖章串的长度。
第二行一共K个字符,表示小豆得到奖章串。
N<=1000 & K<=15

Output

一共K+1行,第i行表示小豆最后奖励等级为i-1的不同的合法兑奖串的个数,可能这个数会很大,结果对10^9 + 7取模。

Sample Input

3 2
NO

Sample Output

1
19
6
提示
最长公共子序列长度0的串有:III;
最长公共子序列长度2的串有:NON, NNO, NOO, ONO,INO, NIO;
除去NOI,余下的19(26-6-1)种为最长公共子序列长度为1。

analysis

发现其实和上道题 BZOJ 3864 一样,只是多了层限制,不能出现 \(NOI\) 字样,那么我们多开设一维记录前两位的状态就好啦。

具体的可以看看代码学习学习。

code

#include<bits/stdc++.h>
using namespace std;
const int maxk=16,mod=1e9+7;

char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{
    x=0;
    T f=1, ch=getchar();
    while (!isdigit(ch) && ch^'-') ch=getchar();
    if (ch=='-') f=-1, ch=getchar();
    while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
    x*=f;
}

template<typename T>inline void write(T x)
{
    if (!x) { putchar('0'); return ; }
    if (x<0) putchar('-'), x=-x;
    T num=0, ch[20];
    while (x) ch[++num]=x%10+48, x/=10;
    while (num) putchar(ch[num--]);
}

typedef int iarr[maxk+1];
iarr a,f,g,ans;
int v[1<<maxk][3],w[3][3];
int F[2][1<<maxk][3];
char ch[maxk+1];
int main()
{
    int n,m;read(n);read(m);
    scanf("%s",ch+1);
    for (int i=1; i<=m; ++i)
    {
        if (ch[i]=='N') a[i]=0;
        if (ch[i]=='O') a[i]=1;
        if (ch[i]=='I') a[i]=2;
    }
    for (int i=0; i<(1<<m); ++i)
    {
        for (int j=0; j<m; ++j) f[j+1]=f[j]+(i>>j&1);
        for (int j=0; j<3; ++j)
        {
            for (int k=1; k<=m; ++k)
                if (a[k]==j) g[k]=f[k-1]+1;
                else g[k]=max(f[k],g[k-1]);
            v[i][j]=0;
            for (int k=1; k<=m; ++k)
                if (g[k]>g[k-1]) v[i][j]|=1<<(k-1);
        }
    }
    w[0][0]=1,w[0][1]=0,w[0][2]=0;
    w[1][0]=1,w[1][1]=2,w[1][2]=0;
    w[2][0]=1,w[2][1]=0,w[2][2]=3;
    for (int j=0; j<(1<<m); ++j)
        for (int l=0; l<3; ++l) F[0][j][l]=0;
    int x=0;F[0][0][0]=1;
    for (int i=0; i<n; ++i,x^=1)
    {
        for (int j=0; j<(1<<m); ++j)
            for (int l=0; l<3; ++l) F[x^1][j][l]=0;//memset(F[x^1],0,sizeof(F[x^1]));
        for (int j=0; j<(1<<m); ++j)
            for (int l=0; l<3; ++l) if (F[x][j][l])
                for (int k=0; k<3; ++k)
                    if (w[l][k]<3) F[x^1][v[j][k]][w[l][k]]=(F[x^1][v[j][k]][w[l][k]]+F[x][j][l])%mod;
    }
    for (int i=0,v; i<(1<<m); ++i)
    {
        v=__builtin_popcount(i);
        for (int l=0; l<3; ++l) ans[v]=((long long)ans[v]+F[x][i][l])%mod;
    }
    for (int i=0; i<=m; ++i) write(ans[i]),puts("");
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/G-hsm/p/11318560.html