Description
给出一个长度为N由B、W、X三种字符组成的字符串S,你需要把每一个X染成B或W中的一个。
对于给出的K,问有多少种染色方式使得存在整数a,b,c,d使得:
1<=a<=b<c<=d<=N
Sa,Sa+1,...,Sb均为B
Sc,Sc+1,...,Sd均为W
其中b=a+K-1,d=c+K-1
由于方法可能很多,因此只需要输出最后的答案对109+7取模的结果。
Input
第一行两个正整数N,K
第二行一个长度为N的字符串S
Output
一行一个整数表示答案%(109+7)。
Sample Input
5 2
XXXXX
XXXXX
Sample Output
4
HINT
对于100%的数据,1<=N<=106,1<=K<=106
用f[i][j][k]表示到了第i位,状态是j(即0是没有连续段长为k的,1是B有W没有,2是BW都有),k是这一位选了什么(0是B,1是W)
保证连续的B后面一定有一个W,连续的W后有一个B,答案就是f[n+1][2][0]
假设这一位选B显然有
f[i][j][0]=f[i-1][j][1]+f[i-1][j][0]
if(i-k+1到i没有W)f[i][1][0]=f[i][1][0]+f[i-k][0][1];
然而这样会有重复,由于f[i][0][0]是乱转移,中间有可能已经有B了,所以:
if(i-k+1到i没有W)f[i][0][0]=f[i][0][0]-f[i-k][0][1];
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define maxn 1000100
#define mod 1000000007
using namespace std;
int w[maxn],b[maxn],dp[maxn][3][2],n,k;
char s[maxn];
int inline get(int x){
// if(x>=mod)return x-mod;
// else if(x<=-mod)return x+mod;
return x%mod;
}
int main(){
scanf("%d%d%s",&n,&k,s+1);
s[++n]='X';
for(int i=1;i<=n;++i){
b[i]=b[i-1]+(s[i]=='B');
w[i]=w[i-1]+(s[i]=='W');
}
dp[0][0][1]=1;
for(int i=1;i<=n;++i){
if(s[i]=='B'||s[i]=='X')for(int j=0;j<3;++j)dp[i][j][0]=get(dp[i-1][j][1]+dp[i-1][j][0]);
if(s[i]=='W'||s[i]=='X')for(int j=0;j<3;++j)dp[i][j][1]=get(dp[i-1][j][1]+dp[i-1][j][0]);
if(i<k)continue;
if(s[i]=='B'||s[i]=='X')if(w[i]==w[i-k]){
dp[i][1][0]=get(dp[i][1][0]+dp[i-k][0][1]);
dp[i][0][0]=get(dp[i][0][0]-dp[i-k][0][1]);
} if(s[i]=='W'||s[i]=='X')if(b[i]==b[i-k]){
dp[i][2][1]=get(dp[i][2][1]+dp[i-k][1][0]);
dp[i][1][1]=get(dp[i][1][1]-dp[i-k][1][0]);
}
}
printf("%d\n",(dp[n][2][0]%mod+mod)%mod);
}