目录

Plan Holidays

2748

F - Plan Holidays

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll mod = 998244353;
#define int long long
struct nd {
    int mx[2][2];
    nd() {
        mx[0][0] = mx[0][1] = mx[1][0] = mx[1][1] = 0;
    }
    nd operator+(const nd& b) const {
        nd z;
        z.mx[0][0] = max({mx[0][0] + b.mx[0][0],mx[0][0] + b.mx[1][0],mx[0][1] + b.mx[0][0]});
        z.mx[0][1] = max({mx[0][0] + b.mx[0][1],mx[0][0] + b.mx[1][1],mx[0][1] + b.mx[0][1]});
        z.mx[1][0] = max({mx[1][0] + b.mx[0][0],mx[1][0] + b.mx[1][0],mx[1][1] + b.mx[0][0]});
        z.mx[1][1] = max({mx[1][0] + b.mx[0][1],mx[1][0] + b.mx[1][1],mx[1][1] + b.mx[0][1]});
        return z;
    }
};

// nd ept = nd();

struct seg {
    int n;
    vector<nd> tree;
    seg(int _n) : n(_n) {
        tree.assign(4*(n+1),nd());
    }
  
    void build(int l, int r, int p, vector<int>& a) {
        if (l == r) {
            tree[p].mx[1][1] = a[l];
            return;
        }
        int mid = (l + r) >> 1;
        build(l,mid,p<<1,a);
        build(mid+1,r,p<<1|1,a);
        tree[p] = tree[p<<1] + tree[p<<1|1];
    }

    nd qr(int l, int r, int p, int x, int y) {
        // if (r < x || l > y) {
        //     return ept;
        // }
        if (l >= x && r <= y) {
            return tree[p];
        }
        int mid = (l + r) >> 1;
        if (y <= mid) {
            return qr(l,mid,p<<1,x,y);
        } 
        if (x >= mid + 1) {
            return qr(mid+1,r,p<<1|1,x,y);
        }
        return qr(l,mid,p<<1,x,y) + qr(mid+1,r,p<<1|1,x,y);
    }
};


void solve() {
    int n, k;
    cin >> n >> k;
    vector<int> a(n+1);
    vector<int> pre(n+1);
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        pre[i] = pre[i-1] + a[i]; 
    }
    seg tree(n);
    tree.build(1,n,1,a);
    int ans = 1e18;
    // cout << tree.qr(1,1,n,1,5).mx[1][0] << endl;
    for (int i = 1; i + k - 1 <= n; i++) {
        ans = min(ans,pre[i+k-1] - pre[i-1] - tree.qr(1,n,1,i,i+k-1).mx[0][0]);
        if (i + k <= n) {
            ans = min(ans, pre[i + k] - pre[i - 1] -tree.qr(1, n, 1, i, i + k).mx[0][0]);
        }
    }
    cout << ans << '\n';
}   

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int tt = 1;
    cin >> tt;
    while (tt--) {
        solve();
    }
    return 0;
}

转移矩阵不存在幺元

        // if (r < x || l > y) {
        //     return ept;
        // }

这个写法有问题,只能使用稳健写法。


        if (l >= x && r <= y) {
            return tree[p];
        }
        int mid = (l + r) >> 1;
        if (y <= mid) {
            return qr(l,mid,p<<1,x,y);
        } 
        if (x >= mid + 1) {
            return qr(mid+1,r,p<<1|1,x,y);
        }
        return qr(l,mid,p<<1,x,y) + qr(mid+1,r,p<<1|1,x,y);

为啥要选k + 1 ?

[1,100,1] k = 2

这个情况,选择三个反而更优。

下面反证不可能选择k+2的情况:

区间[L,R]是被选中区间,且满足R - L + 1= k + 2

L 根据题目要求必被选中, L + 1 分两种情况讨论

  1. L + 1 付钱, L + 2 不付钱, 那 L 就没有必要存在,可以砍掉L,让L+1成为左端点
  2. L + 1 不付钱, L + 2 为了让L+1不付钱必须选中,所以L和L+1都可以被砍掉,只剩下L+2

上一篇 Endless holiday
下一篇 Words Lists