zzuli 1895

Description

985有一个长度为n的0-1串,已知他最多可以修改k次(每次修改一个字符即0->1 或者 1->0),他想知道连续的全1子串最长是多少。

Input

第一行输入一个整数t,代表有t组测试数据。

每组数据第一行输入两个整数n,k分别代笔上面的信息。

注:1 <= t <= 12,1 <= n <= 100000,0 <= k <= 100000。

Output

一个整数代表可以得到的最大长度。

Sample Input

2
6 3
010100
6 2
010100

Sample Output

5
4

HINT

这道题应该使用尺取法写的,不过用二分也能写。 最长的纯1串肯定是从一个数开始的(好像是废话),所以定义状态dp[i] 以 i 元素开始的最长纯1串。
代码解释的比较详细:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#define N 200000
using namespace std;
typedef long long ll;
int arr[N],dp[N],id[N],num[N];
char str[N];
int erfen(const int *num,int l,int r,int k);
int main()
{
    int t,n,i,j,k;
    scanf("%d",&t);
    while(t--)
    {
        memset(dp,0,sizeof(dp));
        memset(num,0,sizeof(id));
        scanf("%d%d",&n,&k);
        scanf(" %s",str+1);
        for(i=1; i<=n; i++)
           arr[i] = str[i] - '0';
        int tail = 0,head = 0;
        for(i=1; i<=n; i++)
        {
            num[i] = num[i-1];
            if(arr[i] == 0)
                num[i] += 1;
        } //num数组统计前i个元素含有 0 的个数。
        int maxx = 0;
        for(i=1; i<=n; i++)
        {
            dp[i] = erfen(num,i,n,k); //二分从i点可以延伸的最大长度
           // printf("%d ",dp[i]);
            if(dp[i] > maxx)
                maxx = dp[i];
        }
        printf("%d\n",maxx);
    }
    return 0;
}
int erfen(const int *num,int l,int r,int k)
{
    int l2 = l;
    if(num[r] - num[l-1] <= k)
        return  r-l+1;//r-l+1;
    int mid = (r+l)/2;
    while(1)
    {
        if(num[mid]-num[l2-1] == k)
        {
            int j = mid;
            while(num[j] == num[mid])
            {
                j += 1;
            }
            return j-l2;
        }

        else if(num[mid]-num[l2-1] > k)
            r = mid-1;
        else
            l = mid+1;
        mid = (r+l)/2;
    }
}

这道题是66ms过的,而尺取法是20ms左右,尺取法还是快一点,我把尺取法的代码也放在这里好了。

#include <stdio.h>
#include <string.h>
#define N 1000000+100
int arr[N];
char str[N];
int max(int a,int b)
{
    if(a >= b)
        return a;
    return b;
}
int main()
{
    int t,n,i,k;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&k);
        scanf(" %s",str+1);
        for(i=1; i<=n; i++)
        {
            arr[i] = str[i] - '0';
        }
        int tail = 0,head = 0;
        for(i=1; i<=n; i++)
        {
            if(arr[i]==0 && --k<0)
                break;
            ++tail;
        }
        arr[n+1] = 0;
        while(arr[tail+1] == 1)
            tail++;
        int maxx = tail;
        if(tail >= 1)
            head = 1;
        for(tail; tail<n; )
        {
            if(arr[tail+1] == 1)
                tail++;
            else
            {
               while(arr[head] != 0)
                  head += 1;
               head++; tail++;
            }
            maxx = max(tail-head+1,maxx);
        }
        printf("%d\n",maxx);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值