codeforces1196D RGB Substring (hard version) dp
网址:http://codeforces.com/contest/1196/problem/D2
题意:
给出$n,k$表示字符串长度和子段长。问把原串的长度为$k$的子串变成无限长的循环字符串$“RGBRGBRGB......”$的子串的最小字符更换次数。
题解:
$dp[i][j]$表示主串的位置是$i$,末字母编号是$j$时,$str[1$~$i]$的代价。则转移方程是$dp[i][j]=dp[i-1][j]+(str[i]!=ch[(i+j)])$,然后$dp[i][j]-dp[i-k][j]$就是字符串在$str[i-k+1$~$i]$上的最小更换次数,取最小值即可。
AC代码:(本代码可通过$D1$)
#include <bits/stdc++.h>
using namespace std;
char ch[3]={'R','G','B'};
int dp[200005][3];
int main()
{
int T,n,m;
cin>>T;
string str,str2[3];
while(T--)
{
cin>>n>>m;
cin>>str;
dp[0][0]=(str[0]!=ch[0]);
dp[0][1]=(str[0]!=ch[1]);
dp[0][2]=(str[0]!=ch[2]);
for(int i=1;i<n;++i)
{
dp[i][0]=dp[i-1][0]+(str[i]!=ch[(i)%3]);
dp[i][1]=dp[i-1][1]+(str[i]!=ch[(i+1)%3]);
dp[i][2]=dp[i-1][2]+(str[i]!=ch[(i+2)%3]);
}
/*for(int i=0;i<3;++i)
for(int j=0;j<n;++j)
cout<<dp[j][i]<<" ";
cout<<endl;*/
int res1=dp[m-1][0],res2=dp[m-1][1],res3=dp[m-1][2];
for(int i=m;i<n;++i)
{
res1=min(res1,dp[i][0]-dp[i-m][0]);
res2=min(res2,dp[i][1]-dp[i-m][1]);
res3=min(res3,dp[i][2]-dp[i-m][2]);
}
int minn=min(res1,min(res2,res3));
cout<<minn<<endl;
}
return 0;
}

浙公网安备 33010602011771号