Beijing Guards UVALive - 3177 长城守卫 二分+贪心

版权声明:本文为博主原创文章,未经博主允许不得转载,欢迎添加友链。 https://blog.csdn.net/qq_42835910/article/details/89790831

     Beijing was once surrounded by four rings of city walls: the Forbidden City Wall, the Imperial CityWall, the Inner City Wall, and nally the Outer City Wall. Most of these walls were demolished in the 50s and 60s to make way for roads. The walls were protected by guard towers, and there was a guard living in each tower. The wall can be considered to be a large ring, where every guard tower has exaetly two neighbors. 

     The guard had to keep an eye on his section of the wall all day, so he had to stay in the tower. This is a very boring job, thus it is important to keep the guards motivated. The best way to motivate a guard is to give him lots of awards. There are several different types of awards that can be given: the Distinguished Service Award, the Nicest Uniform Award, the Master Guard Award, the Superior Eyesight Award, etc. The Central Department of City Guards determined how many awards have to be given to each of the guards. An award can be given to more than one guard. However, you have to pay attention to one thing: you should not give the same award to two neighbors, since a guard cannot be proud of his award if his neighbor already has this award. The task is to write a program that determines how many different types of awards are required to keep all the guards motivated.

分析:如果n为偶数,ans = max{r[i]+r[i+1]};

          如果n为奇数。贪心+二分答案:设p种礼物满足分配。设第一个人的礼物是1~r[1](1~p在最左边),左右分配:编号为偶数的尽量往前取,编号为奇数的尽量往后取(因为最后的一个n是奇数,要与最开始的1达到最大的不匹配)。

#include <cstdio>
#include <algorithm>
using namespace std; 
const int N = 100000 + 5;
int requires[N], lefts[N], rights[N], n;
// left[i]表示第i个人在左边拿到的数量。 
bool ok(int p){
	int x = requires[1], y = p - requires[1]; // 第一个人拿最左边的,并以此边界 
	lefts[1] = x; rights[1] = 0;
	for(int i = 2; i <= n; i++){
		if(i%2 == 1){// odd; 尽量拿右边的礼物 
			rights[i] = min(y-rights[i-1], requires[i]);
			lefts[i] = requires[i] - rights[i];
		}else{ // even, 尽量拿左边的礼物 
			lefts[i] = min(x - lefts[i-1], requires[i]);
			rights[i] = requires[i] - lefts[i];
		}
	}
	return lefts[n] == 0; //是否拿了左边的,即是否和第1个人有相同的 
}

int main(int argc, char** argv) {	
	while( ~scanf("%d",&n) && n){
		int sum = 0;
		for(int i = 1; i <= n; i++){
			scanf("%d",&requires[i]);
			sum += requires[i];
		}
		if( n == 1){ // n == 1时 
			printf("%d\n",requires[1]);
			continue;
		}
		requires[n+1] = requires[1];
		int left = 0, right = sum;
		for(int i = 1; i <= n; i++)
			left = max(left, requires[i]+requires[i+1]);
		if(n % 2 == 1){ // odd		
			while(left < right){
				int mid = left +(right - left)/2;
				if(ok(mid)) right = mid;
				else left = mid+1;
			}
		}
		printf("%d\n",left);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42835910/article/details/89790831
今日推荐