TJOI2018 Day1 T3

http://www.elijahqi.win/archives/3278
题意:给定一个串s lenth<=15 给一个n 再给一个字符集 问n长度的串中不出现noi 且n长度的串与s串的lcs为等级 求每个等级有多少个不同的n长度的串

题解:http://www.elijahqi.win/archives/3265 这个为基础

在原有的dp数组上再增加一维[0/1/2]分别表示当前串的末尾构成的noi的长度为多少了

然后枚举八种情况 分别转移即可

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int mod=1e9+7;
int g[20],h[20],w[20],S,dp[2][33768][3],mp[3][3],trans[33768][3],bin[20],n,m,ans[20];char s1[20];
inline int make(int *h){int s=0;
    for (int i=1;i<=n;++i){
        s|=(h[i]-h[i-1])*bin[i-1];
    }return s;
}
inline void make1(int *g,int s){g[0]=0;
    for (int i=1;i<=n;++i) g[i]=g[i-1],g[i]+=(s&bin[i-1])>0;
}
inline void pre(){
    for (int owo=0;owo<3;++owo){
        for (int s=0;s<=S;++s){
            make1(g,s);memset(h,0,sizeof(h));
            for (int i=1;i<=n;++i)
                h[i]=max(h[i-1],max(g[i],(w[owo]==s1[i])*(g[i-1]+1)));
            trans[s][owo]=make(h);
        }
    }
}
inline void inc(int &x,int v){x=x+v>=mod?x+v-mod:x+v;}
inline int bc(int x){int tmp=0;
    for (int i=0;i<=n;++i) if (x&bin[i]) ++tmp;return tmp;
}
int main(){
    freopen("party.in","r",stdin);
    freopen("party.out","w",stdout);
    scanf("%d%d",&m,&n);w[0]='N';w[1]='O';w[2]='I';
    for (int i=0;i<=15;++i) bin[i]=1<<i;
    scanf("%s",s1+1);S=(1<<n)-1;pre();int pre=0,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;dp[pre][0][0]=1;
    for (int i=0;i<m;++i){
        memset(dp[now],0,sizeof(dp[now]));
        for (int s=0;s<=S;++s){
            for (int j=0;j<=2;++j){
                for (int owo=0;owo<=2;++owo){
                    if (owo==2&&j==2) continue;
                    int y=trans[s][owo];
                    inc(dp[now][y][mp[j][owo]],dp[pre][s][j]);
                }
            }
        }pre^=1;now^=1;
    }
    for (int s=0;s<=S;++s)
        for (int j=0;j<=2;++j) inc(ans[bc(s)],dp[pre][s][j]);
    for (int i=0;i<=n;++i) printf("%d\n",ans[i]);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值