AC 社交距离(分类讨论 + 贪心 / 二分)

一种新型疾病,COWVID-19,开始在全世界的奶牛之间传播。

Farmer John 正在采取尽可能多的预防措施来防止他的牛群被感染。

Farmer John 的牛棚是一个狭长的建筑物,有一排共 N 个牛栏。

有些牛栏里目前有奶牛,有些目前空着。

得知“社交距离”的重要性,Farmer John 希望使得 D 尽可能大,其中 D 为最近的两个有奶牛的牛栏的距离。

例如,如果牛栏 3 和 8 是最近的有奶牛的牛栏,那么 D=5。

最近两头奶牛新来到 Farmer John 的牛群,他需要决定将她们分配到哪两个之前空着的牛栏。

请求出他如何放置这两头新来的奶牛,使得 D 仍然尽可能大。

Farmer John 不能移动任何已有的奶牛;他只想要给新来的奶牛分配牛栏。

输入格式

输入的第一行包含 N。

下一行包含一个长为 N 的字符串,由 0 和 1 组成,描述牛棚里的牛栏。

0 表示空着的牛栏,1 表示有奶牛的牛栏。

字符串中包含至少两个 0,所以有足够的空间安置两头新来的奶牛。

输出格式

输出 Farmer John 以最优方案在加入两头新来的奶牛后可以达到的最大 D 值(最近的有奶牛的牛栏之间的距离)。

数据范围

2≤N≤105

输入样例:

14
10001001000010

输出样例:

2

样例解释

在这个例子中,Farmer John 可以以这样的方式加入奶牛,使得牛栏分配变为 10x010010x0010,其中 x 表示新来的奶牛。

此时 D=2。

不可能在加入奶牛之后取到更大的 D 值。

---------------------------------------------------------------------------------------------------------------------------------

  原文链接:https://blog.csdn.net/qq_46456049/article/details/123751222 

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, m;
char s[N];
int a[N];
int main(){
	cin >> n;
	cin >> s + 1;
	for(int i = 1; i <= n; i ++ ){
		if(s[i] == '1')
		    a[++ m] = i;
	}
	if(m == 0)
	    cout << n - 1 << endl;
	else{
		int minx = N;
		for(int i = 1; i < m; i ++ ){
			minx = min(minx, a[i + 1] - a[i]);
		}
		
		//两头牛在同一个区间
		int y = max((a[1] - 1) / 2, (n - a[m]) / 2);
		for(int i = 1; i < m; i ++ ){
			y = max(y, (a[i + 1] - a[i])/3);
		} 
		
		//两头牛放在不同区间
		int y1 = a[1] - 1;
		int y2 = n - a[m];
		if(y1 < y2)
		    swap(y1, y2);
		for(int i = 1; i < m; i ++ ){
			int d = (a[i + 1] - a[i]) / 2;
			if(d >= y1){
				y2 = y1;
				y1 = d;
			}
			else if(d > y2)
			    y2 = d;
		}
		cout << min(minx, max(y, y2)) << endl;
	}
	return 0;
}

 

 看到题解里有二分的QAQ
链接:https://www.acwing.com/solution/content/103514/

思路
关于一些比较多人问的问题,我放在下面了
总体目标:查找最短距离的最大值

目标:距离——>二分查找牛棚距离

key:1)插入新的牛之后不会大于插入之前的距离r,那么也就是说,我们初始的距离范围是[1,r]。
2)关键是如何写好check

实现:
1)先找到之前的距离
2)check函数:
1、cnt是放了几头牛,p是前一头牛的位置,x是目前判断的距离,p+x就是插入的位置,每check一次我们就要初始化一次p的值,即 p = 1-x(因为一开始判断能否插入牛的位置是1)。
2、遍历每一个有牛的位置判断能不能在它的后面插一个牛,即 p+x+x <=a[i] ,加一头牛就是加一个距离x
3、最后,最后一头牛只要比最后的位置小就行
4、false:放不完两头牛 true:放完了两头牛

问题:
1)为什么要从p=1-x开始,而不从p=1开始?
答: 要保证在p+x处插入,且插入的范围是从[1,n],如果是p=1,范围将改变。初始的p+x就会等于1+x,而不是1。

2)为什么要p+=x?
其实很关键的一个点就是,check我们保证输出true时是放了大于两头牛的。换而言之,我们要把区间内的方案列举完,而且存在的方案要大于2,x才能成为我们的ans。

#include<iostream>
using namespace std;

const int N=100005;
int n,m,ans;
int a[N];
char s[N];


bool check(int x) {
    int p=1-x,cnt=0;//cnt不一定恒等于2,小于2代表方案不合理,大于等于2代表方案合理 
    for(int i=1; i<=m; i++) {
        while(p+x+x<=a[i]) p+=x,cnt++;//如果符合条件,p就往后移动x的距离,牛的头数就加一头 
        p=a[i];//令p=a[i],p就是前一头牛的位置 
    }
    while(p+x<=n) p+=x,cnt++; //因为存在插入位置没包含最后一个位置n的情况,所以需要继续往后加牛,直到加到不能加位置 
    return cnt>=2;//如果加入的牛的数量大于等于2,证明我们的方案是可行的,即x是一种答案 
}

int main() {
    cin>>n;
    cin>>s+1;
    for(int i=1; i<=n; i++)
        if(s[i]=='1') a[++m]=i;
    int l=1,r=n;
    for(int i=1; i<m; i++) r=min(r,a[i+1]-a[i]);
    while(l<=r) {
        int mid=l+r>>1;
        if(check(mid)) {
            ans=mid;
            l=mid+1;
        } else r=mid-1;
    }
    cout<<ans;
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值