Codeforces 204D

dp[i]表示前i个字母里面一定有连续k个’B’的情况总数
dp1[i]表示前i个字母里面只有第i号位置出现有连续k个’B’情况总数
然后答案的话就是直接枚举第一次出现连续k个’B’的位置,
然后情况总数*后面一定出现连续k个’W’情况总数

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int N=1e6+100;
const int mod=1e9+7;
typedef __int64 LL;
LL mi[N];
void init(){
    int n=1e6;
    mi[0]=1;
    for(int i=1;i<=n;i++){
        mi[i]=mi[i-1]*2%mod;
    }
}

char ss[N];
int n,k;
int cnt[N][3];
int getid(char ch){
    if(ch=='B')return 0;
    if(ch=='W')return 1;
    return 2;
}
int getnum(int l,int r){
    if(l)return cnt[r][1]-cnt[l-1][1];
    else return cnt[r][1];
}
void getdp(LL dp[N],LL dp1[N]){
    //printf("%s\n",ss);
    for(int i=0;i<n;i++){
        if(i){
            for(int j=0;j<3;j++)cnt[i][j]=cnt[i-1][j];
        }
        else {
            for(int j=0;j<3;j++)cnt[i][j]=0;
        }
        cnt[i][getid(ss[i])]++;

        if(i){
            if(ss[i]=='X')dp[i]=dp[i-1]*2%mod;
            else dp[i]=dp[i-1];
        }
        else {
            dp[i]=0;
        }

        dp1[i]=0;
        if(i==k-1){
            int num=getnum(i-k+1,i);
            if(!num){
                dp1[i]=1;
            }
        }
        else if(i==k){
            int num=getnum(i-k+1,i);
            if(!num&&ss[i-k]!='B'){
                dp1[i]=1;
            }
        }
        else if(i>k){
            int num=getnum(i-k+1,i);
            if(!num&&ss[i-k]!='B'){
                dp1[i]=(mi[cnt[i-k-1][2]]-dp[i-k-1]+mod)%mod;
            }
        }

        dp[i]=(dp[i]+dp1[i])%mod;
    }
}

LL dp[2][N],dp1[2][N];
int main(){
    #ifdef DouBi
    freopen("in.cpp","r",stdin);
    #endif // DouBi
    init();
    while(scanf("%d%d",&n,&k)!=EOF){
        scanf("%s",ss);
        getdp(dp[0],dp1[0]);
//        for(int i=0;i<n;i++){
//            printf("%d %I64d %I64d\n",i,dp[0][i],dp1[0][i]);
//        }
        for(int i=0;i<n;i++){
            if(ss[i]=='B'){
                ss[i]='W';
            }
            else if(ss[i]=='W'){
                ss[i]='B';
            }
        }
        for(int i=0;i<n/2;i++){
            swap(ss[i],ss[n-1-i]);
        }
        getdp(dp[1],dp1[1]);
//        for(int i=0;i<n;i++){
//            printf("%d %I64d %I64d\n",i,dp[1][i],dp1[1][i]);
//        }

        int ans=0;
        for(int i=0;i<n-1;i++){
            ans+=dp1[0][i]*dp[1][n-1-(i+1)]%mod;
            ans%=mod;
        }
        printf("%d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值