UVALive 3177 Beijing Guards

题目大意:给定一个环,每个人要得到Needi种物品,相邻的人之间不能得到相同的,问至少需要几种。

首先把n=1特判掉。

然后在n为偶数的时候,答案就是max(Needi+Needi+1)(包括(1,n))。

证明:把物品排成一行,只要一个人从左边开始取,下一个人从右边开始取,以此类推,保证不会重复。

然后在n为奇数的时候,答案就不好做了。

观察一下这道题,发现答案满足可二分性,不如思考一下check怎么写。

因为n为奇数时难点就在看n与1是否矛盾上,只要解决了这个问题,一切好说。

不难发现答案下界就是max(Needi+Needi+1)(包括(1,n)),上界开大一点无所谓的。

还是把物品排成一行,第一个人从左边开始取。

要使第n个人和第1个人尽量不矛盾,不如让他从最后开始选。

然后n-1就从前面开始选。

一路逆推回来,你会发现:让2从左边开始选。

什么?1不是从左边开始选的吗?为什么2也从左边开始选呢?

因为我们二分的mid是可以保证(i,i+1)之间一定不矛盾的,所以从2开始做就是为了n号点与1号点的尽量不矛盾。

换句话说,不会转过圈的都是一定满足的,所以就是要把它们以一种合适的方式排布,成全n和1这一对。

感觉在下一盘惊天大棋?

至于维护方式,也是比较巧(套)妙(路)的。

有mid个物品,第一个人选了前Need[1]个,我们就把这些物品分成左右,[1,Need[1]]和[Need[1]+1,mid]。

记L[i]和R[i]表示i在左边/右边取了多少个。

对于偶数位,由推导,我们尽量从左边选。

L[i]=min(Need[i],Need[1]-L[i-1]),R[i]=Need[i]-L[i]。

对于奇数位,尽量从右边选。

R[i]=min(Need[i],(mid-Need[1])-R[i-1]),L[i]=Need[i]-R[i]。

最后,因为1把L全部取完了,我们只要看L[n]==0即可。

真是妙。

#include    <iostream>
#include    <cstdio>
#include    <cstdlib>
#include    <algorithm>
#include    <vector>
#include    <cstring>
#include    <queue>
#include    <complex>
#include    <stack>
#define LL long long int
#define dob double
#define FILE "3177"
using namespace std;

const int N = 100010;
int n,Ned[N],L[N],R[N];

inline int gi(){
  int x=0,res=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}
  while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
  return x*res;
}

inline bool check(int mid){
  int Lh=Ned[1],Rh=mid-Ned[1];
  L[1]=Lh;R[1]=0;
  for(int i=2;i<=n;++i)
    if(i&1){
      R[i]=min(Ned[i],Rh-R[i-1]);
      L[i]=Ned[i]-R[i];
    }
    else{
      L[i]=min(Ned[i],Lh-L[i-1]);
      R[i]=Ned[i]-L[i];
    }
  return L[n]==0;
}

int main()
{
  freopen(FILE".in","r",stdin);
  freopen(FILE".out","w",stdout);
  while(n=gi()){
    for(int i=1;i<=n;++i)Ned[i]=gi();
    if(n==1){printf("%d
",Ned[1]);continue;}
    int Ans=Ned[n]+Ned[1];
    for(int i=1;i<n;++i)
      Ans=max(Ans,Ned[i]+Ned[i+1]);
    if(n&1){
      int l=Ans,r=Ans*2;Ans=r;
      while(l<=r){
        int mid=(l+r)>>1;
        if(check(mid))r=mid-1,Ans=mid;
        else l=mid+1;
      }
    }
    printf("%d
",Ans);
  }
  fclose(stdin);fclose(stdout);
  return 0;
}
Beijing Guards
原文地址:https://www.cnblogs.com/fenghaoran/p/7651411.html