UVA 1335 Beijing Guards(二分答案)

入口: https://cn.vjudge.net/problem/UVA-1335

【题意】

n个人为成一个圈,其中第i个人想要r[i]种不同的礼物,相邻的两个人可以聊天,炫耀自己的礼物。如果两个相邻的人拥有同一种礼物,则双方都会很不高兴,问最少需要多少种不同的礼物才能满足所有人的需求,假设每种礼物有无限多个

 

 

【分析】

[蓝书例题]

如果n为偶数的话,ans = max{r[i] + r[i + 1] },(r[n + 1] = r[1]).
如果n为奇数的话,上述式子就不成立了,因为n个人围成圈的话,头尾两人是相邻的,但他们都是奇数位置的人,不能满足奇数尽量取前,偶数尽量取后。所以要用到二分的方法搜索答案,但最关键的是怎么判断说一个值是否可以满足条件。
 

最优分配方案定为已知p种礼物,第一个人取1~r1,偶数号人从小到大取,奇数号人从大到小取(满足相邻不重复),如果最后1和n满足不重复说明合理。然后判断函数用了两个数组left[i],right[i]分别表示第i个人从小到大礼物种类的个数和从大到小礼物种类的个数,最后left[n]如果等于0,那么p满足。根据单调性,二分(最小)答案。

【代码】

#include<cstdio>
#include<iostream>
#define debug(x) cerr<<#x<<" "<<x<<'\n';
using namespace std;
inline int read(){
	register char ch=getchar();register int x=0;
	for(;ch<'0'||ch>'9';ch=getchar());
	for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+ch-'0';
	return x;
}
const int N=1e5+5;
int n,a[N],le[N],ri[N];
inline bool check(int now){
	int x=a[1],y=now-a[1];
	le[1]=x,ri[1]=0;
	for(int i=2;i<=n;i++){
		if(i&1){
			ri[i]=min(y-ri[i-1],a[i]);
			le[i]=a[i]-ri[i];
		}
		else{
			le[i]=min(x-le[i-1],a[i]);
			ri[i]=a[i]-le[i];
		}
	}
	return !le[n];
}
int main(){
	for(;n=read();){
		int l=0,r=0,mid,ans=0;
		for(int i=1;i<=n;i++) a[i]=read();a[n+1]=a[1];
		if(n==1){printf("%d\n",a[1]);continue;}
		for(int i=1;i<=n;i++) l=max(l,a[i]+a[i+1]),r=max(r,a[i]*3);
		if(n&1){
			while(l<=r){
				mid=l+r>>1;
				if(check(mid)){
					ans=mid;
					r=mid-1;
				}
				else{
					l=mid+1;
				}
			}
		}
		else{
			ans=l;
		}
		printf("%d\n",ans);
	}
	return 0;
}

 

posted @ 2019-01-24 17:41  神犇(shenben)  阅读(269)  评论(0编辑  收藏  举报