网址: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; }