575 div3RGB Substring (hard version)——思维-

【题目描述】
The only difference between easy and hard versions is the size of the input.

You are given a string s
consisting of n

characters, each character is ‘R’, ‘G’ or ‘B’.

You are also given an integer k
. Your task is to change the minimum number of characters in the initial string s so that after the changes there will be a string of length k that is a substring of s

, and is also a substring of the infinite string “RGBRGBRGB …”.

A string a
is a substring of string b if there exists a positive integer i such that a1=bi, a2=bi+1, a3=bi+2, …, a|a|=bi+|a|−1

. For example, strings “GBRG”, “B”, “BR” are substrings of the infinite string “RGBRGBRGB …” while “GR”, “RGR” and “GGG” are not.

You have to answer q

independent queries.

Input

The first line of the input contains one integer q

(1≤q≤2⋅105) — the number of queries. Then q

queries follow.

The first line of the query contains two integers n
and k (1≤k≤n≤2⋅105) — the length of the string s

and the length of the substring.

The second line of the query contains a string s
consisting of n

characters ‘R’, ‘G’ and ‘B’.

It is guaranteed that the sum of n
over all queries does not exceed 2⋅105 (∑n≤2⋅105

).

Output

For each query print one integer — the minimum number of characters you need to change in the initial string s

so that after changing there will be a substring of length k in s

that is also a substring of the infinite string "RGBRGBRGB ...".

Example
Input

3
5 2
BGGGG
5 3
RBRGR
5 5
BBBRR

Output

1
0
3

【题目分析】
题目要求给定串改变最少的字符使串的一个子串变成一个无限长串 " R G B R G B R G B … … " "RGBRGBRGB……" "RGBRGBRGB"的一个子串
我自己看完后十分懵逼,因为没什么想法,既没有说改变的是哪一部分子串,也没有说变成什么样子,还需要最小。在看到别人的博客以后才恍然大悟,我们不必要将目光局限在改变的那一小部分子串上,我们如果将最终改变的子串拓展成和给定串长度相同的串,无外乎三种,分别以 R R R G G G B B B开头,我们就分别计算如果将串变成那三种样子哪些位置需要改变(需要改变的位置记为1,不需要改变的位置记为0,然后用一个前缀和数组进行维护),然后再找长度为k的子串中需要改变最少的。
觉得自己这种抽象能力不太够,还需要多进行锻炼。
【AC代码】

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<climits>
#include<cstdlib>
#include<cmath>

using namespace std;

typedef long long ll;

const int MAXN=200005;
char s[MAXN];
const char t[4]="RGB";
int sum[MAXN][3];
int ans;

int main()
{
	int T,n,k;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&k);
		scanf("%s",s);
		ans=INT_MAX;
		//memset(sum,0,sizeof(sum));
		sum[0][0]=sum[0][1]=sum[0][2]=0;
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<3;j++)
			{
				if(s[i]!=t[(i+j)%3])
				{
					sum[i+1][j]=sum[i][j]+1;
				}
				else
				{
					sum[i+1][j]=sum[i][j];
				}
			}
		}
		for(int i=0;i<=n-k;i++)
		{
			for(int j=0;j<3;j++)
			{
				ans=min(ans,sum[i+k][j]-sum[i][j]);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值