「POI2010」积木 Blocks

Posted ympc2005

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「POI2010」积木 Blocks相关的知识,希望对你有一定的参考价值。

单调栈

可以发现子序列的平均数不小于k就可以使子序列的每个数都不小于k

将每个数减去k,则子序列之和非负即可

记 si = a1 + a2 +....+ ai - k*i

考虑序列的两个端点 l, r

对于 l: l1 < l2 && sl1 <=  sl2, 则l1 比 l2 优

对于 r:   r1 < r2 && sr1 <= sr2 则r2 比 r1 优

 从0到n 将可能最优 l 加入单调栈中,可以发现栈是单调递增的

从n到1 的可能最优 r 的是单调递减的

每次将当前栈中满足sr - sl ≥ 0的 l 都弹出,最后一个被弹出的就是最优的l

而且对与更小的 r,它的值会更大,所以被弹出的l更不会用到

#include <bits/stdc++.h>
using namespace std;

const int N = 1e6 + 5;
typedef long long LL;

int n, m, a[N], k, ans, zhan[N], top;
LL s[N];

void Solve() {
    ans = top = 0;
    zhan[++top] = 0;
    for (int i = 1; i <= n; i++) {
        s[i] = s[i - 1] + a[i] - k;
        if (s[i] < s[zhan[top]])
            zhan[++top] = i;
    }
    for (int i = n; i; i--) {
        while (s[i] - s[zhan[top]] >= 0 && top) top--;
        ans = max(ans, i - zhan[top + 1]);
    }
    cout << ans << " ";
}

int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    for (int i = 1; i <= m; i++) {
        scanf("%d", &k);
        Solve();
    }
    return 0;
}

 

以上是关于「POI2010」积木 Blocks的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 2086: [Poi2010]Blocks

BZOJ 2086: [Poi2010]Blocks

bzoj 2086 [Poi2010]Blocks 单调栈

BZOJ 2086: [Poi2010]Blocks

洛谷P3503 [POI2010]KLO-Blocks 单调栈

[POI2010]KLO-Blocks——一道值得思考的题