Codeforces Round #575 (Div. 3) - D2. RGB 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 nn 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 ii such that a_1 = b_i , a_2 = b_{i + 1} a_3 = b_{i + 2}, ..., a_{|a|} = b_{i + |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\cdot 10^5) — the number of queries. Then qq queries follow.

The first line of the query contains two integers n and k (1≤k≤n≤2\cdot 10^5) — the length of the string s and the length of the substring.

The second line of the query contains a string s consisting of nn characters 'R', 'G' and 'B'.

It is guaranteed that the sum of nn over all queries does not exceed 2\cdot 10^5 (∑n≤2\cdot 10^5).

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

Note

In the first example, you can change the first character to 'R' and obtain the substring "RG", or change the second character to 'R' and obtain "BR", or change the third, fourth or fifth character to 'B' and obtain "GB".

In the second example, the substring is "BRG".

题目大意:

给一个长度为n的字符串s,找一段长度为k的子串,将该子串变成无限循环串“...RGBRGB...”的子串所需要的修改字符数最少,输出需要修改的最少字符数。

官方题解链接

题目分析:

这题如果直接统计最长连续RGB子串,再与k比较的方法是错的,一开始wa了两发, 还以为哪里写挫了,后来发现错了,例如“BBBGR”的串,n = k = 5时,只需要修改中间3个,经过思考,其实我们只要串与RGB串进行比对,找到s串中长度为k且与无限RGB串匹配最多的子串成功匹配的字符数, 事实上,我们只要将R开头,G开头和B开头的无限循环串与s串进行匹配,实现这一过程我们只要是偏移量分别为0, 1, 2,然后将s串下标加上偏移量对3取模得到RGB串的下标,我们循环遍历s串,当得到的串长度大于k时,如果最右边的第i位偏移后匹配,则cnt ++,同时最左边第i - k位偏移后匹配,我们就要使cnt --,使子串长度始终为k,然后ans = max(ans,cnt)。

很显然看出这样的时间复杂度是O(n)的,我也是这样写的,但是写挫了,结果只把输入规模较小的easy版过了,hard版超时了,下面我也会把写挫的代码给粘贴出来,引以为戒。

AC代码:

只过easy的

#include 
#include 
#include 
using namespace std;
const int N = 2e5 + 5;
char s[N];
int visx[N], visy[N], visz[N];
int main()
{
    int q;
    cin >> q;
    while (q --){
        int n, k;
        cin >> n >> k;
        int cnt = 1;
        int ans = 0;
        scanf("%s", s + 1);
        memset(visx, 0, sizeof(visx));
        memset(visy, 0, sizeof(visy));
        memset(visz, 0, sizeof(visz));
        int x = 0, y = 0, z = 0;
        for (int i = 1; i <= n; i ++){
            if ((i % 3 == 1 && s[i] == 'R') || (i % 3 == 2 && s[i] == 'G') || (i % 3 == 0 && s[i] == 'B')){
                x ++;
                visx[i] = 1;
            }
            if ((i % 3 == 1 && s[i] == 'G') || (i % 3 == 2 && s[i] == 'B') || (i % 3 == 0 && s[i] == 'R')){
                y ++;
                visy[i] = 1;
            }
            if ((i % 3 == 1 && s[i] == 'B') || (i % 3 == 2 && s[i] == 'R') || (i % 3 == 0 && s[i] == 'G')){
                z ++;
                visz[i] = 1;
            }
            if (i > k){
                x -= visx[i - k];
                ans = max(ans, x);
                y -= visy[i - k];
                ans = max(ans, y);
                z -= visz[i - k];
                ans = max(ans, z);
            }
            if (i == k){
                ans = max(ans, x);
                ans = max(ans, y);
                ans = max(ans, z);
            }

        }
        if (ans >= k)printf("0\n");
        else printf("%d\n", k - ans);

    }
    return 0;
}

都过了的

#include 
#include 
#include 
using namespace std;
const int N = 2e5 +5;
char s[N];
int main()
{
    int q;
    cin >> q;
    char a[] = {"RGB"};
    while (q --){
        int n, k;
        cin >> n >> k;
        scanf("%s", s + 1);
        int len = strlen(s + 1);
        int ans = 0;
        for (int i = 0; i < 3; i ++){
            int cnt  = 0;
            for (int j = 1; j <= k; j ++){
                if (s[j] == a[(j + i) % 3])cnt ++;
            }
            ans = max(ans, cnt);
            for (int j = k + 1; j <= n; j ++){
                if (s[j] == a[(j + i) % 3])cnt ++;
                if (s[j - k] == a[(i + j - k) % 3])cnt --;
                ans = max(ans, cnt);
            }
        }
        if (ans >= k)printf("0\n");
        else printf("%d\n",k - ans);
    }
    return 0;
}

 

你可能感兴趣的:(Codeforces Round #575 (Div. 3) - D2. RGB Substring (hard version))