QDUOJ 河老师的新年礼物(尺取法)

河老师的新年礼物

发布时间: 2017年1月1日 15:11   最后更新: 2017年1月1日 15:13   时间限制: 1000ms   内存限制: 256M

描述

河老师的新年礼物是一个长度为n的ab串,他想要找出最长的一个子串使得这个子串中每个字符都相等,他称之为“最优子串”。当然对河老师来说这个问题太简单了,于是他加了一个条件:他可以改变这个串中的某些字符,但一次只能改变一个字符,最多能改变k次。河老师想要知道,在可以对串进行改变的前提下,这个ab串的“最优子串”的长度是多少。

输入

第一行是一个整数T,代表T组测试数据,
第二行是两个整数 n , k (1 ≤ n ≤ 100 000, 0 ≤ k ≤ n) 
第三一个ab串,长度为n

输出

输出“最优子串”的长度

样例输入1  复制
2
4 2
abba
8 1
aabaabaa
样例输出1
4
5
查看隐藏信息

 

给你一串字符串和k个修改字符串的机会,让这个字符串获得最长连续相同子串

 

题解:所谓尺取法,顾名思义,就是一把尺子(固定某一条件),不断向右(向左)移动,不断更新我们要的答案。在这里,我们只要从左往右,让修改的字符个数从0慢慢增加到k,中途将字符改成同一个字符(a改成b或者b改成a都行),最后修改字符数固定为k,每次向右移动时,如果字符串需要修改,那就改掉右面的字符,将之前最左边的字符换回来。那么我们可以用一个队列去实现。

如果你看不懂上面也没关系,我再讲具体一些。我们从左边开始,扫描字符串。如果遇到a,那就把a丢进队列,如果遇到b,且此时队列中b的个数不超过k的话,就把b丢进去。如果b的个数等于k,且又遇到一个b,那就记录下此时队列长度,这个时候队列里k个b可以当作a,所以可以记录队列元素个数,更新答案最大值。之后将队列前面元素弹出,直到弹出一个b,再将新的b压进队列……一直扫描直到字符串尾。

接下来将a和b互换,重复上面步骤,更新最大值。最后输出最大值。

第一次写的队列是存取了修改字符的下标,更新最大值为当前下标与弹出下标的差。在codeforces上能过,qduoj就WA,这种方法效率会比上面的高一些,毕竟队列里存入的只是部分值,还特地考虑了k=0的情况,应该还是数据(shui)的问题吧>_<

 

#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;

int main()
{
    int t,c,n,k,maxa,maxb,max,i;
    char s[100005];
    queue<int> q;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&k);
        scanf(" %s",s);
        max=0;
        while(q.size()) q.pop();
        maxa=0;c=0;
        for(i=1;i<=n;i++){
            if(s[i-1]=='a'){
                q.push(1);
            }
            if(s[i-1]=='b'){
                q.push(2);
                if(c<k) c++;
                else{
                    while(q.size()&&q.front()==1) q.pop();
                    if(q.size()) q.pop();
                }
            }
            if(q.size()>maxa) maxa=q.size();
        }
        while(q.size()) q.pop();
        maxb=0;c=0;
        for(i=1;i<=n;i++){
            if(s[i-1]=='b'){
                q.push(2);
            }
            if(s[i-1]=='a'){
                q.push(1);
                if(c<k) c++;
                else{
                    while(q.size()&&q.front()==2) q.pop();
                    if(q.size()) q.pop();
                }
            }
            if(q.size()>maxb) maxb=q.size();
        }
        if(maxa>maxb) max=maxa;
        else max=maxb;
        printf("%d\n",max);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/yzm10/p/7392694.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值