题目:codevs1513、BZOJ1863。
题目大意:有n个人围成一个圈,每个人需要$a[i]$个颜色不同的勋章,且相邻两个人不能拿到同样颜色的勋章。求至少需要准备多少种不同颜色的勋章。
解题思路:首先我们可以二分答案,但如何判断答案的正确性呢?我们可以用dp。
设$f[i]$表示第i个人在不与前一个人冲突的情况下,与第1个人最多冲突的个数,$g[i]$表示第i个人在不与前一个人冲突的情况下,与第一个人最少冲突的个数,可得
$f[i]=min(a[i],a[1]-g[i-1])$
$g[i]=max(0,a[i]+a[i-1]+a[1]-f[i-1]-x)(x为当前二分到的答案)$
最后如果g[n]不为0则答案有效。
C++ Code:
#include<cstdio>
#include<algorithm>
using namespace std;
int n,a[20005],f[20005],g[20005];
bool ok(int x){
f[1]=g[1]=a[1];
for(int i=2;i<=n;++i){
f[i]=min(a[i],a[1]-g[i-1]);
g[i]=max(0,a[i]+a[i-1]+a[1]-f[i-1]-x);
}
return !g[n];
}
int main(){
scanf("%d",&n);
int s=0;
for(int i=1;i<=n;++i)scanf("%d",&a[i]),s+=a[i];
int l=0,r=s,ans=s;
for(int i=1;i<n;++i)l=max(l,a[i]+a[i+1]);
while(l<=r){
int mid=(l+r)>>1;
if(ok(mid)){
r=mid-1;
ans=mid;
}else
l=mid+1;
}
printf("%d\n",ans);
return 0;
}