Problem
Here lies a row of a number of bricks each painted either black or white. With a single stroke of your brush, you can overpaint a part of the row of bricks at once with either black or white paint. Using white paint, all the black bricks in the painted part become white while originally white bricks remain white; with black paint, white bricks become black and black ones remain black. The number of bricks painted in one stroke, however, is limited because your brush cannot hold too much paint at a time. For each brush stroke, you can paint any part of the row with any number of bricks up to the limit.
In the first case of the sample input, the initial colors of four bricks are black, white, white, and black. You can repaint them to white, black, black, and white with two strokes: the first stroke paints all four bricks white and the second stroke paints two bricks in the middle black.
Your task is to calculate the minimum number of brush strokes needed to change the brick colors as specified. Never mind the cost of the paints.
Input
The input consists of a single test case formatted as follows.
n k
s
t
The first line contains two integers n and k (1≤k≤n≤500000). n is the number of bricks in the row and k is the maximum number of bricks painted in a single stroke. The second line contains a string s of n characters, which indicates the initial colors of the bricks. The third line contains another string t of n characters, which indicates the desired colors of the bricks. All the characters in both s and t are either B or W meaning black and white, respectively.
Output
Output the minimum number of brush strokes required to repaint the bricks into the desired colors.
Sample Input 1
4 4
BWWB
WBBW
Sample Output 1
2
Sample Input 2
4 3
BWWB
WBBW
Sample Output 2
3
Sample Input 3
4 3
BWWW
BWWW
Sample Output 3
0
Sample Input 4
7 1
BBWBWBW
WBBWWBB
Sample Output 4
4
Solution
油漆一列黑白格,每一笔可涂1..k个格子,全黑或全白。
问从起始状态涂成目标状态,最少涂几笔?
DP, 设f[i] (i∈[1..n]) 表示涂好前i个黑白格的最少笔数,由于1笔可涂1..k格,f[i]与f[j] (max(0,i-k)<=j<=i-1) 有关。
而在一段一段去涂的时候,对于一个长度在k以内的小区间,设小区间内有x个颜色连续的小段,显然最少需涂ceil(x/2)笔。
连续的小段可以求前缀和.
状态转移方程:
f[i] = f[i-1], s[i]==t[i];
f[i] = min{f[j] + ceil((sum[i]-sum[j+1])/2 + 1} , max(i-k) <= j < i
初始:f[0]=0,f[i]=INF
目标:f[n]
n<=5* 105 10 5 , 考虑单调队列优化. 维护 2*f[j] - sum[j+1] 递增且位置下标距i小于k。
Code
#include <cstdio>
const int MX = 500001;
const int INF = 0x3f3f3f3f;
struct data{
int pos,val;
data(){}
data(int p,int v) {
pos=p;
val=v;
}
}Que[MX]; // 2*f[j] - b[j+1]
int f[MX],b[MX],n,k,l,r;
char s[MX],t[MX];
int Min(int a,int b) {
return a<b?a:b;
}
int Query() {
return l<r ? Que[l+1].val : INF;
}
void Update(int p,int v) {
while (l<r&&Que[r].val>=v) r--;
Que[++r]=data(p,v);
while (l<r&&Que[l+1].pos+k<=p) l++;//since 2+3=5 and |[2,3,4]|==3,2 should go out of the queue. 2+3-1<p equals 2+3<=p
}
int main() {
scanf("%d%d",&n,&k);
scanf("%s%s",s+1,t+1);
for (int i=1;i<=n;++i) b[i]=b[i-1]+(t[i]!=t[i-1]),f[i]=INF;
l=r=-1;
Update(0,-1);//Init();
for (int i=1;i<=n;++i) {
if (s[i]==t[i]) f[i]=f[i-1];
else f[i] = Min(f[i],(Query()+b[i]+1)/2+1);
Update(i,f[i]+f[i]-b[i+1]);
}
printf("%d\n",f[n]);
return 0;
}