一种新型疾病,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;
}