Problem D: 985的0-1串难题

Problem D: 985的0-1串难题

Time Limit: 1 Sec   Memory Limit: 128 MB
Submit: 260   Solved: 75

Submit Status Web Board

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

宇神:

解法一:发现最后的结果是线性的,我们二分答案,把问题变成判定性问题。 对于当前的二分值mid,判断它的合法性即:是否存在一个mid的连续段使得该段的0字符总数 <= k。 时间复杂度:O(T * n * log(n))。

解法二:考虑dp,dp[i]表示以第i个字符开始的最优连续段。 那么我们只要找到最大的j(i <= j <= n)使得[i, j]里面0字符总数 <= k即可。 可以先统计0字符的前缀和,然后每次二分即可。最后结果就是max(dp[i]) (1 <= i <= n)。 时间复杂度:O(T * n * log(n))。

菜鸡:

记录0~i之间有多少0保存才cnt[i]中

则区间[n,m]中有a[m]-a[n-1]个0

长度(含有字符数)为n-m+1

所以比较k与a[m]-a[n-1]从而进行区间更新

并记录出现过的最大长度即为结果

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. #include<stdio.h>   
  2. #include<algorithm>   
  3. using namespace std;   
  4. char s[100200];   
  5. int cnt[100200];   
  6. int main() {   
  7.     int T;   
  8.     scanf("%d",&T);   
  9.     while(T--) {   
  10.         int n,k;   
  11.         scanf("%d %d",&n,&k);   
  12.         scanf("%s",s);   
  13.         cnt[0]=(s[0]=='0'?1:0);   
  14.         for(int i=1; i<n; i++) {   
  15.             cnt[i]=cnt[i-1];   
  16.             if(s[i]=='0')   
  17.                 cnt[i]++;   
  18.         }   
  19.         if(cnt[n-1]<=k)   
  20.             printf("%d\n",n);   
  21.         else {   
  22.             int l=0,res=0;   
  23.             for(int i=0; i<n; i++) {   
  24.                 while(k<cnt[i]-(l==0?0:cnt[l-1]))   
  25.                     l++;   
  26.                 res=max(res,i-l+1);   
  27.             }   
  28.             printf("%d\n",res);   
  29.         }   
  30.     }   
  31.     return 0;   
  32. }   

宇神:

解法一:发现最后的结果是线性的,我们二分答案,把问题变成判定性问题。
对于当前的二分值mid,判断它的合法性即:是否存在一个mid的连续段使得该段的0字符总数 <= k。
时间复杂度:O(T * n * log(n))。


解法二:考虑dp,dp[i]表示以第i个字符开始的最优连续段。
那么我们只要找到最大的j(i <= j <= n)使得[i, j]里面0字符总数 <= k即可。
可以先统计0字符的前缀和,然后每次二分即可。最后结果就是max(dp[i]) (1 <= i <= n)。
时间复杂度:O(T * n * log(n))。


菜鸡:

记录0~i之间有多少0保存才cnt[i]中

则区间[n,m]中有a[m]-a[n-1]个0

长度(含有字符数)为n-m+1

所以比较k与a[m]-a[n-1]从而进行区间更新

并记录出现过的最大长度即为结果


[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. #include<stdio.h>   
  2. #include<algorithm>   
  3. using namespace std;   
  4. char s[100200];   
  5. int cnt[100200];   
  6. int main() {   
  7.     int T;   
  8.     scanf("%d",&T);   
  9.     while(T--) {   
  10.         int n,k;   
  11.         scanf("%d %d",&n,&k);   
  12.         scanf("%s",s);   
  13.         cnt[0]=(s[0]=='0'?1:0);   
  14.         for(int i=1; i<n; i++) {   
  15.             cnt[i]=cnt[i-1];   
  16.             if(s[i]=='0')   
  17.                 cnt[i]++;   
  18.         }   
  19.         if(cnt[n-1]<=k)   
  20.             printf("%d\n",n);   
  21.         else {   
  22.             int l=0,res=0;   
  23.             for(int i=0; i<n; i++) {   
  24.                 while(k<cnt[i]-(l==0?0:cnt[l-1]))   
  25.                     l++;   
  26.                 res=max(res,i-l+1);   
  27.             }   
  28.             printf("%d\n",res);   
  29.         }   
  30.     }   
  31.     return 0;   
  32. }   

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值