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
Sample Output
4
数据约定
对于20%的数据,N<=20
对于50%的数据,N<=2000
对于100%的数据,1<=N<=10^6,1<=K<=10^6
HINT
Source
题解:
我的算法和网上别人的好像不太一样。。。
每次转移都是一段B或一段W,所以记dp[i][j][k]为算完i位,j=0,1,2表示没有完成B,没有完成W,BW都完成了,k表示上一个是B还是W。
普通的dp直接枚举从哪一位转移,长度大于k强制修改j。
时间复杂度O(n^2)。
看到转移是把一段dp求和,记录dp的前缀和即可。
时间复杂度O(n)。
#include <stdio.h>
#include <algorithm>
using namespace std;
//long long
const int mod = 1000000007;
const int maxn = 1200000;
int n , k;
char z[maxn];
int dp[maxn][3][3] , last[maxn][3] , sum[maxn][3][3];
void work () {
int i , j , l;
scanf ( "%d%d" , &n , &k );
scanf ( "%s" , z + 1 );
if ( k > n ) {
printf ( "0\n" );
return ;
}
j = n;
for ( i = n ; i >= 1 ; i-- ) {
if ( j > i ) j = i;
while ( j >= 0 && z[j] != 'W' ) j--;
last[i][1] = j;
}
j = n;
for ( i = n ; i >= 1 ; i-- ) {
if ( j > i ) j = i;
while ( j >= 0 && z[j] != 'B' ) j--;
last[i][2] = j;
}
//for ( i = 1 ; i <= n ; i++ ) printf ( "%d %d\n" , last[i][1] , last[i][2] );
//if ( z[1] != 'W' ) {
// if ( k != 1 ) dp[1][0][1] = 1;
// else dp[1][1][1] = 1;
//}
dp[0][0][1] = dp[0][0][2] = sum[0][0][1] = sum[0][0][2] = 1;
//if ( z[1] != 'B' ) dp[1][0][2] = 1;
//sum[1][0][1] = dp[1][0][1]; sum[1][1][1] = dp[1][1][1];
//sum[1][0][2] = dp[1][0][2];
for ( i = 1 ; i <= n ; i++ ) {
if ( last[i][2] <= i ) {
dp[i][0][2] += (sum[i-1][0][1] - (last[i][2]!=0?sum[last[i][2]-1][0][1]:0) + mod) % mod;
dp[i][0][2] %= mod;
}
l = i - 1 - k + 1;
if ( last[i][1] <= i ) {
if ( last[i][1] <= l ) {
dp[i][0][1] += (sum[i-1][0][2] - sum[l][0][2] + mod) % mod;
dp[i][0][1] %= mod;
dp[i][1][1] += (sum[l][0][2] - (last[i][1]!=0?sum[last[i][1]-1][0][2]:0) + mod) % mod;
dp[i][1][1] %= mod;
}
else {
dp[i][0][1] += (sum[i-1][0][2] - (last[i][1]!=0?sum[last[i][1]-1][0][2]:0) + mod) % mod;
dp[i][0][1] %= mod;
}
}
//printf ( "%d\n" , l );
/* printf ( "%d %d %d %d\n" , dp[1][0][1] , dp[1][0][2] ,
(sum[i-1][0][1] - sum[last[i][2]-1][0][1]),
(sum[i-1][0][2] - sum[last[i][1]-1][0][2]) );*/
if ( last[i][2] <= i ) {
if ( last[i][2] <= l ) {
dp[i][1][2] += (sum[i-1][1][1] - sum[l][1][1] + mod) % mod;
dp[i][1][2] %= mod;
dp[i][2][2] += (sum[l][1][1] - (last[i][2]!=0?sum[last[i][2]-1][1][1]:0) + mod) % mod;
dp[i][2][2] %= mod;
}
else {
dp[i][1][2] += (sum[i-1][1][1] - (last[i][2]!=0?sum[last[i][2]-1][1][1]:0) + mod) % mod;
dp[i][1][2] %= mod;
}
}
if ( last[i][1] <= i ) {
dp[i][1][1] += (sum[i-1][1][2] - (last[i][1]!=0?sum[last[i][1]-1][1][2]:0) + mod) % mod;
dp[i][1][1] %= mod;
}
if ( last[i][2] <= i ) {
dp[i][2][2] += (sum[i-1][2][1] - (last[i][2]!=0?sum[last[i][2]-1][2][1]:0) + mod) % mod;
dp[i][2][2] %= mod;
}
if ( last[i][1] <= i ) {
dp[i][2][1] += (sum[i-1][2][2] - (last[i][1]!=0?sum[last[i][1]-1][2][2]:0) + mod) % mod;
dp[i][2][1] %= mod;
}
for ( j = 1 ; j <= 6 ; j++ ) sum[i][(j-1)/2][(j-1)%2+1] = (sum[i-1][(j-1)/2][(j-1)%2+1]+dp[i][(j-1)/2][(j-1)%2+1]) % mod;
}
//for ( i = 0 ; i <= n ; i++ ) printf ( "%d %d %d %d %d %d\n" , dp[i][0][1] , dp[i][0][2] , dp[i][1][1] , dp[i][1][2] , dp[i][2][1] , dp[i][2][2] );
//printf("\n");
//for ( i = 0 ; i <= n ; i++ ) printf ( "%d %d %d %d %d %d\n" , sum[i][0][1] , sum[i][0][2] , sum[i][1][1] , sum[i][1][2] , sum[i][2][1] ,sum[i][2][2] );
printf ( "%d\n" , ((dp[n][2][1] + dp[n][2][2]) % mod + mod ) % mod);
}
int main () {
//FILE *fpr = freopen ( "bzoj3269.in" , "r" , stdin );
//FILE *fpw = freopen ( "bzoj3269.out" , "w" , stdout );
work ();
return 0;
}