1. 程式人生 > >【UVA - 1335】Beijing Guards (貪心,二分)

【UVA - 1335】Beijing Guards (貪心,二分)

題幹:

題目大意:

有n個人為成一個圈,其中第i個人想要r[i]種不同的禮物,相鄰的兩個人可以聊天,炫耀自己的禮物。如果兩個相鄰的人擁有同一種禮物,則雙方都會很不高興,問最少需要多少種不同的禮物才能滿足所有人的需求,假設每種禮物有無限多個。 n<=100000

解題報告:

http://www.cnblogs.com/kickit/p/7619889.html

http://www.bubuko.com/infodetail-645767.html

總之就是偶數個的時候直接貪出相鄰兩者的最大值就可以。

              奇數的時候:先單獨安排第一個,並以這一個為分界線分為左右兩個區域部分,然後剩下的分奇偶進行安排(第奇數個儘量往右安排,第偶數個儘量往左安排),然後安排到最後一個一定是儘量往右安排的,然後我們看這個是否和第一個有衝突就行了,如果沒有衝突那一定是可以的,如果有衝突那一定就是說明我們用的李無數是不夠的,因為我們這樣一定是最優解了。

AC程式碼:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
#define fi first
#define se second
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAX = 2e5 + 5;
int a[MAX];
int L[MAX],R[MAX];
int n;
bool ok(int x) {
	int l=a[1],r=x-a[1];
	L[1]=a[1];R[1]=0;
	for(int i = 2; i<=n; i++) {
		if(i%2==1) {
			R[i] = min(r-R[i-1],a[i]);
			L[i] = a[i]-R[i];
		}
		else {
			L[i] = min(l-L[i-1],a[i]);
			R[i] = a[i]-L[i];
		}
	}
	return L[n]==0;//填L[n]<=0也可以AC,,但是在這裡還是==0比較好理解,因為L和R這兩個陣列都不存在為負情況。
	
}
int main()
{
	while(~scanf("%d",&n)) {
		if(n == 0) break;
		int maxx = 0;
		for(int i = 1; i<=n; i++) {
			scanf("%d",a+i);
			maxx = max(maxx,a[i]+a[i-1]);
		}
		maxx = max(maxx,a[1]+a[n]);
		if(n == 1) {
			printf("%d\n",a[1]);continue;
		}
		else if(n % 2 == 0) {
			printf("%d\n",maxx);continue;
		}
		int l = maxx,r = INF;
		int mid = (l+r)>>1;
		while(l < r) {
			mid = (l+r)>>1;
			if(ok(mid)) r = mid;
			else l = mid+1;
		}
		printf("%d\n",l);
	}
	return 0 ;
 }