CF1367C - Social Distance

题目链接

https://codeforces.com/problemset/problem/1367/C

题目描述

给出一个长为 n n n 01 01 01 字符串和一个整数 k k k 1 ≤ k ≤ n ≤ 2 × 1 0 5 1\le k\le n\le 2\times10^5 1kn2×105),要求将串中的若干个 0 0 0 变成 1 1 1,并且要使得变化后的串中任意相邻的两个 1 1 1 之间至少有 k k k 0 0 0,问最多可以将多少个 0 0 0 变成 1 1 1

解题思路

使用贪心思想,从左到右扫描一遍字符串,必须要保证前k个字符和后k个都字符不包含1,才能将字符0变成1

如果直接暴力枚举的话,肯定会超时哒。

如何记录后k个都字符是否包含1
我们可以使用一个数组来记录从右到左最近一个字符1出现的位置。

r i r_i ri为第 i − n i-n in位最近出现字符1的位置。
例:假如有字符串01001,数组 r r r的值为{2,2,5,5,5}

如何记录前k个字符是否包含1
在从左到右遍历的过程中,使用一个变量loc来保存最近的1的下标即可。

当然,还需要处理边界为0的情况,解决的方法也很简单,就是增加两个“哨兵”:对于第1位为0的情况,loc的初始值设为无穷小;对于第n位为0的情况, r n + 1 r_{n+1} rn+1的值设为无穷大。

使用“哨兵”的好处是减少了很多特判,使程序的逻辑保持连贯。

参考代码

#include <iostream>
using namespace std;
const int MAXN=200004;
int r[MAXN];	
char str[MAXN];
int main(){
	int t,n,k;
	cin>>t;
	while( t-- ) {
	
		int loc = -MAXN*2,ans=0;
		cin>>n>>k;
		cin>>str+1;
		r[ n+1 ] = MAXN*2;
		
		for(int i = n; i >= 1; i--)
			if( str[i] =='1' ) r[i] = i;
			else r[i] = r[i+1];
		
		for(int i=1; i <= n; i++) {
			
			if ( str[i] == '0' && i-loc >= k+1 && r[i]-i >= k+1) {
				loc = i;
				ans++;
			}
			if ( str[i] == '1' )
				 loc = i;		
		}
		cout<<ans<<endl;	
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值