时间:2016-03-19 19:47:11 星期六
题目编号:[2016-03-19][UVALive][3177][Beijing Guards]
题目大意:n个人坐成一圈,给每个人发ai礼物,要求相邻人的礼物不能有相同的,问至少需要多少礼物
分析:
- 如果n是偶数,那么最少需要max(ai + ai+1)中礼物
- 如果n是奇数,那么肯定需要max(ai + ai+1),只多不少,求最小值,二分答案,
方法:
- 二分答案的时候,奇数位的人尽量拿左边的物品,偶数位的人尽量拿右边的物品,不够再从另外一遍拿,
- 以第(0)一个位置需要的数目和二分的答案来划分左右两边,那么最后一个人n-1人,只能从右边拿,不能从左边拿
#include <cstdio>#include <algorithm>using namespace std;#define FOR(x,y,z) for(int (x)=(y);(x)<(z);++(x))const int maxn = 100000 + 10;int n,a[maxn],mleft[maxn],mright[maxn];//left[i] 表示从左边开始拿了i个礼物//通过a[0]来区分左右int ok(int p){ int x = a[0],y = p - a[0]; mleft[0] = a[0],mright[0] = 0; FOR(i,1,n){ if(i&1){ mleft[i] = min(x - mleft[i - 1],a[i]); mright[i] = a[i] - mleft[i]; }else { //看右边能拿的有多少个 mright[i] = min(y - mright[i - 1],a[i]); //不够的从左边拿 mleft[i] = a[i] - mright[i]; } } return mleft[n - 1] == 0;}int main(){ while(~scanf("%d",&n) && n){ FOR(i,0,n) scanf("%d",&a[i]); if(n == 1){ printf("%d\n",a[0]); continue; } int l = 0,r = 0,mid; a[n] = a[0]; FOR(i,0,n) l = max(l , a[i] + a[i + 1]); if(n & 1){ FOR(i,0,n) r = max(r,a[i] * 3); while(l < r){ mid = l + (r - l)/2; if(ok(mid)) r = mid; else l = mid + 1; } } printf("%d\n",l); } return 0;}