题面
??Beijing was once surrounded by four rings of city walls: the Forbidden City Wall, the Imperial City Wall, the Inner City Wall, and finally 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个人,每个人想要有
ri 种不同的物品,相邻的两个人拥有的物品种类不能相同(i和i+1 相邻,n和1相邻),求至少需要多少种物品才能满足条件
解法
二分:
通过手画一些简单的例子可以发现,答案和n 的奇偶性有关:
??如果n为偶数,那么ans=max(ans,ri+ri+1) ,我们从第一位开始放,第一位和第二位显然要不同,所以需要r1+r2种物品,然后看第三位,如果r3≤r1,那么直接将第一位的物品种类放在第三位即可,否则在第三位就还需要多r3?r1种,即答案更新为r2+r3(因为n为偶数,所以奇数位肯定不会和1相邻),以此类推,在第四位则比较和第二位的大小,第五位则比较和第三位的大小……
如果n 为奇数,这种情况就比较麻烦,因为最后一个奇数位会和1相邻,而根据上面的做法,奇数位至少有min{ ri|i=2?k+1,k∈【0,(n?1)/2】}种物品是相同的,所以不能按上面的方法做。
??显然,如果我们将物品种类分为【1,r1】=x和【ans?r1+1,ans】=y两个部分,第一位选取的物品全部在前半部分,那么我们的目标就是要最后一位选取物品全在后半部分
??直接得出ans很难,于是考虑二分,上界R=∑ni=1ri,下界L=max{ ri+ri+1},rn+1=r1
??对于中点mid,设pi表示第i位在前半部分选取了多少种物品,qi 表示第i位在后半部分选取了多少种物品(i>1 )
??如果i为奇数,那么尽量在后半部分选,即qi=min(y?qi?1,r[i]),pi=ri?qi
??否则,尽量在前半部分选,即pi=min(x?pi?1,ri),qi=ri?pi
??最后的判断依据就是pn是否为0
复杂度
O(nlogn)
代码
#include<iostream>
#include<cstdlib>
#include<cstdio>
#define Lint long long int
using namespace std;
const int MAXN=100010;
int p[MAXN],q[MAXN];
int r[MAXN];
int n;
bool check(int lim)
{int x=r[1],y=lim-r[1];p[1]=x,q[1]=0;for(int i=2;i<=n;i++)if( i%2 ){q[i]=min( y-q[i-1],r[i] );p[i]=r[i]-q[i];}else{p[i]=min( x-p[i-1],r[i] );q[i]=r[i]-p[i];}return !p[n];
}
int main()
{int L,R;while( scanf("%d",&n) && n ){for(int i=1;i<=n;i++) scanf("%d",&r[i]);if( n==1 ) { printf("%d\n",r[n]);continue ; }L=0,R=0;r[n+1]=r[1];for(int i=1;i<=n;i++) L=max( L,r[i]+r[i+1] );if( n%2 ){for(int i=1;i<=n;i++) R+=r[i];while( L<=R ){int mid=(L+R)/2;if( check( mid ) ) R=mid-1;else L=mid+1;}}printf("%d\n",L);}return 0;
}