【DP/二分】BZOJ 1863:[Zjoi2006]trouble 皇帝的烦恼
863: [Zjoi2006]trouble 皇帝的烦恼
Time Limit: 1 Sec Memory Limit: 64 MBSubmit: 465 Solved: 240
[Submit][Status][Discuss]
Description
经过多年的杀戮,秦皇终于统一了中国。为了抵御外来的侵略,他准备在国土边境安置n名将军。不幸的是这n名将军羽翼渐丰,开始展露他们的狼子野心了。他们拒绝述职、拒绝接受皇帝的圣旨。秦皇已经准备好了秘密处决这些无礼的边防大将。不过为防兵变,他决定先授予这些将军一些勋章,为自己赢得战略时间。将军们听说他们即将被授予勋章都很开心,他们纷纷上书表示感谢。第i个将军要求得到ai枚不同颜色的勋章。但是这些将军都很傲气,如果两个相邻的将军拥有颜色相同的勋章他们就会认为皇帝不尊重他们,会立即造反(编号为i的将军和编号为i+1的将军相邻;因为他们驻扎的边境可以类似看成一个圆形,所以编号1和编号n的将军也相邻)。皇帝不得不满足每个将军的要求,但对他们的飞扬跋扈感到很气愤。于是皇帝决定铸造尽量少种类的勋章来满足这些狂妄者的要求。请问他至少要铸造多少种颜色的勋章?
Input
第一行有一个整数n(1<=n<=20000)。接下来n行每行一个整数ai,表示第i个将军要求得到多少种勋章。(1<=ai<=100000) 输出一个整数,即最少需要多少种勋章。
Output
4 2 2 1 1
Sample Input
4
Sample Output
HINT告诉我是二分?并卵
题解告诉我f[i],g[i]维护与1相同的勋章上界下界?并卵
代码告诉了我转移方程?代码看不懂。
题解:二分一个勋章个数,f[i]表示和1存在相同勋章个数的最小值,g[i]表示最大值
然后查看f[n]是否为0
为了报复社会 方程大家自己理解。。。(我的已经好理解很多了,主要是下届方程较难理解)
1 #include<cstdio> 2 3 #define maxn 100001 4 5 int min(int a,int b){return a<b?a:b;} 6 int max(int a,int b){return a>b?a:b;} 7 8 inline int in() 9 { 10 int x=0;char ch=getchar(); 11 while(ch<'0'||ch>'9')ch=getchar(); 12 while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=getchar(); 13 return x; 14 } 15 16 int a[maxn+1],f[maxn],g[maxn],n; 17 18 bool judge(int ans) 19 { 20 f[1]=a[1];g[1]=a[1]; 21 for(int i=2;i<=n;i++) 22 { 23 if(a[i]+a[i-1]>ans)return 0; 24 f[i]=min(a[1]-g[i-1],a[i]); 25 g[i]=max(0,a[1]-(ans-a[i-1]-(a[i]-f[i-1]))); 26 if(f[i]<g[i])return 0; 27 } 28 return g[n]==0; 29 } 30 31 int main() 32 { 33 int l=1,r=0,ans; 34 n=in(); 35 for(int i=1;i<=n;i++)a[i]=in(),r+=a[i],r=min(r,250000); 36 while(l<=r) 37 { 38 int mid=(l+r)>>1; 39 if(judge(mid))r=mid-1,ans=mid; 40 else l=mid+1; 41 } 42 printf("%d",ans); 43 return 0; 44 }