CF460C Present

题目链接:https://www.luogu.org/problem/CF460C

思路:

考虑二分答案。

对于这$n$个数,我们可以从左往右,若发现小于当前答案的数,把$[i,i+w]$之间的所有数都加到当前答案的数值,判断总次数与$m$的关系就行了。

对于更新和查询的操作,不妨使用树状数组维护差分数组。

代码:

#include <bits/stdc++.h>
const int MAXN = 100050;
const int INF = 1e9 + 5;
using namespace std;
int n, m, w, Min = INF, l, r, ans, a[MAXN], b[MAXN];
struct Tree_Array {
    int lowbit(int x) { return x & (-x); }
    void add(int pos, int val) {
        for(int i = pos; i <= n; i += lowbit(i))
            b[i] += val;
    }
    int ask(int pos) {
        int sum = 0;
        for(int i = pos; i >= 1; i -= lowbit(i))
            sum += b[i];
        return sum;
    }
}Tree; 
bool check(int x) {
    int cnt = 0, last = 0;
    memset(b, 0, sizeof(b));
    for(int i = 1; i <= n; i++) {
        Tree.add(i, a[i] - x - last);
        last = a[i] - x;
    }
    for(int i = 1; i <= n; i++) {
        int res = Tree.ask(i);
        if(res < 0) {
            cnt += -res;
            if(cnt > m)
                return false;
            Tree.add(i, -res);
            Tree.add(i + w, res);
        }
    }
    return true;
}
int main() {
    cin >> n >> m >> w;
    for(int i = 1; i <= n; i++) {
        cin >> a[i];
        Min = min(Min, a[i]);
    }
    l = Min, r = Min + m;
    while(l <= r) {
        int mid = (l + r) >> 1;
        if(check(mid)) {
            ans = mid;
            l = mid + 1;
        }
        else
            r = mid - 1;
    }
    cout << ans << endl;
    return 0;
}
原文地址:https://www.cnblogs.com/BeyondLimits/p/11367947.html