【二分答案模板】真题-ACM-ICPC 2017 Asia HongKong-E

上链接:E - 题库 - 计蒜客 

大致题意

为保证各个5G基站之间信号的干扰最小,公司希望最大限度地拉开基站之间的距离,现给出L个候选的基站建设位置,并希望在这L个候选位置中选出K个位置建设基站,从而保证所有基站之间的最小距离最大。

稍作整理翻译后可以很明显地看出来是一道板题——L个元素中选K个元素保证被选元素之间的最小距离最大

看到诸如最小值的最大值最大值的最小值,直接想到二分答案的几个模板,直接上板。

二分模板

求最大值的最小值

while(l<r) {
    int mid=l+r>>1;
    if(check(mid)) {
        r=mid;
    } else {
        l=mid+1;
    }
}

求最小值的最大值

while(l<r) {
    int mid=l+r+1>>1;
    if(check(mid)) {
        l=mid;
    } else {
        r=mid-1;
    }
}

最后答案定格于变量l当中

基本结构一致,注意中值的选取和边界的变换,随后重点就在于check函数了。

中值判断

每一个产生的mid值都有概率成为最终的答案,只需要在check函数中检验当前答案的合理性。

以本题为例,

由于本题需要求最小距离的最大值,故当前被检测的mid值应作为一个可能的最小距离,故可将其放回原数组中判断合理性。

故可遍历原数组(排序后的),统计距离大于mid的区间个数(顶点个数-1),若当前统计的顶点个数大于k,则说明当前mid值过小(这个最小距离太小了,导致产生的比这个最小距离要大的区间数太了,所以可以适量增大这个最小距离mid),同理,若小于k,则说明当前mid值过大,若等于k,则正好说明当前mid值可行,但为了求得最大的最小距离,故将其与mid值过小的情况共同处理,处理好不同统计情况与返回值的关系之后即可。

至于如何查找当前mid所决定的区间(顶点)个数,可通过双指针移动实现,具体方法见代码。

更一般地,对于不同情况的题目,关键就在于在check函数检测当前mid作为最终答案的合理性。

AC代码

#include<bits/stdc++.h>
#define pb(x) push_back(x)
#define pii pair<int,int> 
#define mk(x,y) make_pair(x,y)
using namespace std;
typedef long long ll;
const int N=100005;
const int INF=0x3f3f3f3f;
int a[N];
int n,k;
bool check(int mid) {
	int cnt=1;
	int num=1; 
	for(int i=2;i<=n;i++) {
		if(a[i]-a[cnt]>=mid) {
			cnt=i;
			num++;
		}
	}
	if(num>=k) return true;
	else return false;
}
void solve() {
	for(int i=1;i<=n;i++) {
		cin>>a[i];
	}
	sort(a+1,a+n+1);
	int l=0,r=1e9;
	while(l<r) {
		int mid=l+r+1>>1;
		if(check(mid)) {
			l=mid;
		} else {
			r=mid-1;
		}
	}
	cout<<r<<endl;
}
int main() {
	ios::sync_with_stdio(false);
	while(cin>>n>>k&&n&&k) 
		solve();
	
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值