题目: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 ",ans); return 0; }