BZOJ #2958. 序列染色
题面传送门
感觉很奇怪的dp题/jy
显然要dp,设\(dp_{i,j,h}\)为到了第\(i\)个,当前这一位填了\(h\),目前状态为\(j\),其中\(j=0\)表示没有连续\(k\)个W
,\(j=1\)表示有连续\(k\)个W
但是没有连续\(k\)个B
,\(j=2\)表示有连续\(k\)个B
。
首先来考虑怎么转移\(dp_{i,0,0}\),容易想到直接从\(dp_{i-1,0,0}+dp_{i-1,0,1}\)转移,但是\(dp_{i-1,0,0}\)的转移显然不对,因为可能形成连续一段W
,但是因为到\(i-1\)为止没有这样的段,所以我们认为只有\([i-k+1,i]\)区间能形成连续一段W
,因此减去这样的方案数即可。
然后来考虑怎么转移\(dp_{i,1,0}\),显然有一部分直接从\(dp_{i-1,1,0}\)转移,然后还有新的转移,就从\(dp_{i-k,0,1}\)转移即可。
\(h=1\)部分同理,于是我们可以做到\(O(n)\)的复杂度。
code:
#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define ll long long
#define db double
#define lb long db
#define N (1000000+5)
#define M ((N<<2)+5)
#define K (350)
#define mod 1000000007
#define Mod (mod-1)
#define eps (1e-9)
#define ull unsigned ll
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((k+1)*(x)+(y))
#define R(n) (1ll*rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;
int n,k,Q1[N],Q2[N];char S[N];ll dp[N][3][2];
int main(){
freopen("1.in","r",stdin);
int i,j;scanf("%d%d",&n,&k);scanf("%s",S+1);for(i=1;i<=n;i++) Q1[i]=Q1[i-1]+(S[i]=='B'),Q2[i]=Q2[i-1]+(S[i]=='W');dp[0][0][1]=1;
for(i=1;i<=n;i++) {
if(S[i]^'W') {for(j=0;j<3;j++) dp[i][j][0]=(dp[i-1][j][0]+dp[i][j][0]+dp[i-1][j][1])%mod;if(i>=k&&Q2[i]==Q2[i-k]) dp[i][0][0]=(dp[i][0][0]-dp[i-k][0][1]+mod)%mod,dp[i][1][0]=(dp[i][1][0]+dp[i-k][0][1])%mod;}
if(S[i]^'B') {for(j=0;j<3;j++) dp[i][j][1]=(dp[i-1][j][1]+dp[i][j][1]+dp[i-1][j][0])%mod;if(i>=k&&Q1[i]==Q1[i-k]) dp[i][1][1]=(dp[i][1][1]-dp[i-k][1][0]+mod)%mod,dp[i][2][1]=(dp[i][2][1]+dp[i-k][1][0])%mod;}
}printf("%lld\n",(dp[n][2][0]+dp[n][2][1])%mod);
}