[ZJOI2006]皇帝的烦恼

OJ题号:

BZOJ1863、CodeVS1513

思路:

当$n$为偶数时,可以将原数组按照出现的奇偶性分为两个集合,答案即为两个集合元素最大值之和。
当$n$为奇数时,二分答案,检验时进行动态规划,分别求出当前与$1$的最大冲突值$max$和最小冲突值$min$。
当$min_n=0$时,说明最小不会产生冲突,满足条件。
当$min_n≠0$时,说明在最优情况下同样会产生冲突,不满足条件。
另外需要注意二分时因为答案越小越优,因此当$check()$被满足时应该往小的二分,不然会WA。

 1 #include<cstdio>
 2 #include<cctype>
 3 #include<algorithm>
 4 inline int getint() {
 5     char ch;
 6     while(!isdigit(ch=getchar()));
 7     int x=ch^'0';
 8     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
 9     return x;
10 }
11 const int N=20001;
12 int n;
13 int a[N],min[N],max[N];
14 inline bool check(const int x) {
15     min[1]=max[1]=a[1];
16     for(int i=2;i<=n;i++) {
17         min[i]=std::max(0,a[i]+a[i-1]+a[1]-max[i-1]-x);
18         max[i]=std::min(a[i],a[1]-min[i-1]);
19     }
20     return !min[n];
21 };
22 int main() {
23     n=getint();
24     if(!(n&1)) {
25         int max1=0,max2=0;
26         for(int i=1;i<=n;i++) {
27             if(i&1) {
28                 max1=std::max(max1,getint());
29             }
30             else {
31                 max2=std::max(max2,getint());
32             }
33         }
34         printf("%d\n",max1+max2);
35         return 0;
36     }
37     int tmp=0;
38     for(int i=1;i<=n;i++) {
39         a[i]=getint();
40         tmp=std::max(tmp,a[i]+a[i-1]);
41     }
42     tmp=std::max(tmp,a[n]+a[1]);
43     int l=tmp,r=tmp<<1;
44     while(l<=r) {
45         int mid=(l+r)>>1;
46         if(check(mid)) {
47             r=mid-1;
48         }
49         else {
50             l=mid+1;
51         }
52     }
53     printf("%d\n",l);
54     return 0;
55 }

 

posted @ 2017-08-10 12:41  skylee03  阅读(133)  评论(0编辑  收藏  举报