首页 > 其他 > 详细

[2016-03-19][UVALive][3177][Beijing Guards]

时间:2016-03-19 20:59:43      阅读:127      评论:0      收藏:0      [点我收藏+]
  • 时间: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人,只能从右边拿,不能从左边拿
  1. #include <cstdio>
  2. #include <algorithm>
  3. using namespace std;
  4. #define FOR(x,y,z) for(int (x)=(y);(x)<(z);++(x))
  5. const int maxn = 100000 + 10;
  6. int n,a[maxn],mleft[maxn],mright[maxn];
  7. //left[i] 表示从左边开始拿了i个礼物
  8. //通过a[0]来区分左右
  9. int ok(int p){
  10. int x = a[0],y = p - a[0];
  11. mleft[0] = a[0],mright[0] = 0;
  12. FOR(i,1,n){
  13. if(i&1){
  14. mleft[i] = min(x - mleft[i - 1],a[i]);
  15. mright[i] = a[i] - mleft[i];
  16. }else {
  17. //看右边能拿的有多少个
  18. mright[i] = min(y - mright[i - 1],a[i]);
  19. //不够的从左边拿
  20. mleft[i] = a[i] - mright[i];
  21. }
  22. }
  23. return mleft[n - 1] == 0;
  24. }
  25. int main(){
  26. while(~scanf("%d",&n) && n){
  27. FOR(i,0,n) scanf("%d",&a[i]);
  28. if(n == 1){
  29. printf("%d\n",a[0]);
  30. continue;
  31. }
  32. int l = 0,r = 0,mid;
  33. a[n] = a[0];
  34. FOR(i,0,n) l = max(l , a[i] + a[i + 1]);
  35. if(n & 1){
  36. FOR(i,0,n) r = max(r,a[i] * 3);
  37. while(l < r){
  38. mid = l + (r - l)/2;
  39. if(ok(mid)) r = mid;
  40. else l = mid + 1;
  41. }
  42. }
  43. printf("%d\n",l);
  44. }
  45. return 0;
  46. }




[2016-03-19][UVALive][3177][Beijing Guards]

原文:http://www.cnblogs.com/qhy285571052/p/0971a99752cd7e96580e57039f2202b7.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!