题意
这道题的题意大致就是说
第一行输入两个数n,k那么第一个数代表这个字符串的长度,第二个k代表这个字符串的子串的长度,而且要求这个字串必须是
R
G
B
R
G
B
R
G
B
R
G
B
R
G
B
.
.
.
RGBRGBRGBRGBRGB...
RGBRGBRGBRGBRGB...的一个字串,请问你最少可以修改几个字符,然后让这个字串也是这样的。
思路
这道题还是一个dp,那么如何去分析这道题呢?
首先我们要想到,每一位上的字符都有可能是以R,G,B这三个字母为起点往后延伸k位,考虑动态规划解决本问题,那么就应该这么考虑:
dp[i][j]这个代表了以i为首字母(R,G,B)现在延伸到了第几位(到最后求最小的话,用前缀和对区间进行差分即可)
那么状态转移方程就是
如果这一位符合我们的要求(也就是以i为首字母作为起点,而且枚举到这一位刚好是这一位该枚举的字符了)
d
p
[
i
]
[
j
]
=
d
p
[
i
]
[
j
−
1
]
dp[i][j]=dp[i][j-1]
dp[i][j]=dp[i][j−1]
如果不是
d
p
[
i
]
[
j
]
=
d
p
[
i
]
[
j
−
1
]
+
1
dp[i][j]=dp[i][j-1]+1
dp[i][j]=dp[i][j−1]+1
本位应该枚举的字符是
s
[
(
i
+
j
)
s[(i+j)%3]
s[(i+j)
因为j是首字母的编号,i是枚举到第几位,%3就代表的是以首字符为平台(起点)现在应该是哪个字母
#include<iostream>
#include<string>
using namespace std;
int dp[3][505050];
string s="RGB";
string t;
int main(){
int T;
cin>>T;
while(T--){
int n,k;
cin>>n>>k;
cin>>t;
for(int i=0;i<n;i++){
for(int j=0;j<3;j++){
if(t[i]!=s[(j+i)%3])dp[j][i+1]=dp[j][i]+1;
else dp[j][i+1]=dp[j][i];
}
}
int ans=0x3f3f3f3f;
for(int i=k;i<=n;i++){
for(int j=0;j<3;j++){
ans=min(ans,dp[j][i]-dp[j][i-k]);
}
}
cout<<ans<<endl;
}
}