题意:给定n个守卫战成一圈,每个守卫要r个礼物,然后问需要几种礼物分配给他们才能使得相邻两个守
卫礼物都不同
思路:
1、 当n为偶数的时候,ans = max(p[i]+p[i+1]),可以自己画个图验证;2、 当n为奇数的时候就不满足了,那么我们可以利用二分答案然后判断从而求出最小值。假设有p种礼
物,那么设第一个人的礼物为1~r1,那么不难发现最有的分配的策略一定是这样的:除1以外的其他人,
编号为偶数的人尽量往前取,编号为奇数的人尽量往后取。这样我们只要最后判断第n个人是否与第一个
人有冲突即可。
3、 由于题目并没有要我们输出实际的方案,那么我们只需要记录每个人在[1,r1]和[r1+1,n]这个范围内
取了几个,最后判 断第n个人是否有取[1,r1]范围内的数即可。
4 、注意对于n = 1的情况需要特判。
#include<cstdio>
#include<algorithm>
using namespace std;
int p[100010];
int le[100010],ri[100010];
int n;
//le[i]为第i个人拿的左边的礼物总数
bool test(int u) //测试u个礼物是否足够
{
le[1]=p[1],ri[1]=0;
int x=p[1],y=u-p[1]; //x?y?
for(int i=2;i<=n;i++)
{
if(i%2==0) //尽量拿左边的礼物
{
le[i]=min(p[i],x-le[i-1]);
ri[i]=p[i]-le[i];
}
else //尽量拿右边的礼物
{
ri[i]=min(p[i],y-ri[i-1]);
le[i]=p[i]-ri[i];
}
}
return le[n]==0;
}
int main()
{
while(scanf("%d",&n)&&n)
{
for(int i=1;i<=n;i++)
scanf("%d",&p[i]);
if(n==1) //注意特判n=1
{
printf("%d\n",p[1]);
continue;
}
p[n+1]=p[1];
int L=0,R=0,mid;
for(int i=1;i<=n;i++)
{
L=max(L,p[i]+p[i+1]); //最小范围
R=max(R,p[i]);
}
if(n%2==0)
{
printf("%d\n",L);
continue;
}
else
{
R=3*R; //3倍最大范围
while(L<R)
{
mid = L+(R-L)/2;
if(test(mid))
R=mid;
else L=mid+1;
}
printf("%d\n",L);
}
}
return 0;
}
感想:
真的没想出来,看了题解还是有点不大明白= =,正在慢慢领悟中。。。。