BZOJ 1863 ZJOI 2006 皇帝的烦恼 二分答案

一个简单骗分就是 ans=max{a1+an,ai+ai+1} 。经测试50分。。。似乎有人多对了一个点,不知道有啥特别的技巧?
不妨考虑一下如何判定答案ans,即1与n的最小冲突个数是否为0。
mi[i]表示1与i的最小冲突个数,ma[i]表示1与i的最大冲突个数。那么有:
最多能冲突那么就是全部都冲突了或是分了上一个冲突了的。

ma[i]=min{ai,a1mi[i1]}

最小能冲突那么就是一个都不冲突,否则需要知道最多不冲突的个数,由上一个最多冲突的个数求得。
mi[i]=max{0,ai[ansai1(a1ma[i1])]}

那么 mi[n]==0就表示当前答案可行,所以二分答案即可。

#include 
#include 
using namespace std;
#define FOR(i,j,k) for(i=j;i<=k;i++)
int read() {
    int s = 0, f = 1; char ch = getchar();
    for (; ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') f = -1;
    for (; '0' <= ch && ch <= '9'; ch = getchar()) s = s * 10 + ch - '0';
    return s * f;
}

int main() {
    static int a[20005], ma[20005], mi[20005];
    int n = read(), i, ans = 0, l, r, mid;
    FOR(i,1,n) a[i] = read();
    FOR(i,2,n) ans = max(ans, a[i] + a[i - 1]);
    l = ans, r = ans * 2;
    while (l <= r) {
        mid = l + r >> 1;
        ma[1] = mi[1] = a[1];
        FOR(i,2,n) {
            ma[i] = min(a[i], a[1] - mi[i - 1]);
            mi[i] = max(0, a[i] - (mid - a[i - 1] - (a[1] - ma[i - 1])));
        }
        if (!mi[n]) r = mid - 1;
        else l = mid + 1;
    }
    printf("%d", l);
    return 0;
}

1863: [Zjoi2006]trouble 皇帝的烦恼

Time Limit: 1 Sec Memory Limit: 64 MB
Submit: 510 Solved: 265

Description

经过多年的杀戮,秦皇终于统一了中国。为了抵御外来的侵略,他准备在国土边境安置n名将军。不幸的是这n名将军羽翼渐丰,开始展露他们的狼子野心了。他们拒绝述职、拒绝接受皇帝的圣旨。秦皇已经准备好了秘密处决这些无礼的边防大将。不过为防兵变,他决定先授予这些将军一些勋章,为自己赢得战略时间。将军们听说他们即将被授予勋章都很开心,他们纷纷上书表示感谢。第i个将军要求得到ai枚不同颜色的勋章。但是这些将军都很傲气,如果两个相邻的将军拥有颜色相同的勋章他们就会认为皇帝不尊重他们,会立即造反(编号为i的将军和编号为i+1的将军相邻;因为他们驻扎的边境可以类似看成一个圆形,所以编号1和编号n的将军也相邻)。皇帝不得不满足每个将军的要求,但对他们的飞扬跋扈感到很气愤。于是皇帝决定铸造尽量少种类的勋章来满足这些狂妄者的要求。请问他至少要铸造多少种颜色的勋章?

Input

第一行有一个整数n(1<=n<=20000)。接下来n行每行一个整数ai,表示第i个将军要求得到多少种勋章。(1<=ai<=100000) 输出一个整数,即最少需要多少种勋章。

Sample Input

4 2 2 1 1

Sample Output

4

你可能感兴趣的:(BZOJ,省选,二分,——动态规划——)