P2418 yyy loves OI IV

P2418 yyy loves OI IV
有两种转移情况,一种是差值在范围内用线段树查找转移,一种是同段连续的作为一段来转移。
注意旧的一段已经结束了新的一段要+1

#include<bits/stdc++.h>
using namespace std;
#define pii pair<int, int>
#define mkp make_pair
#define pb push_back
#define ls(x) (x << 1)
#define rs(x) ((x << 1) + 1)

const int N = 1e6+10, inf = 1e9 + 7;
int n, m, q, a[N], pre[N], dp[N], mn[N*4], p[N];
void upd(int x, int l, int r, int q, int k) {
    if (l == r) {mn[x] = min(mn[x], k); return;}
    int mid = (l + r) / 2;
    if (mid >= q) upd (ls(x), l, mid, q, k);
    else upd(rs(x), mid + 1, r, q, k);
    mn[x] = min(mn[ls(x)], mn[rs(x)]);
}
int que(int x, int l, int r, int ql, int qr) {
    if (l >= ql && r <= qr) return mn[x];
    int mid = (l + r) / 2, res = inf;
    if (mid >= ql) res = min(res, que(ls(x), l, mid, ql, qr));
    if (mid < qr) res = min(res, que(rs(x), mid + 1, r, ql, qr));
    return res;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    pre[0] = n + 1;
    int mxn = n*2 + 1;
    for (int i = 1; i <= n * 8 + 4; i++) mn[i] = inf;
    for (int i = 1; i <= n; i++) 
        cin >> a[i], pre[i] = pre[i - 1] + ((a[i] == 1) ? 1 : (-1));
    for (int i = 1; i <= n; i++) dp[i] = inf;
    dp[0] = 0;
    upd (1, 1, mxn, pre[0], 0);
    int lst = 0, preans = 0;
    for (int i = 1; i <= n; i++) {
        //对于连续一段来说只能由合法答案或是同段最小值转移
        if (lst != a[i]) lst = a[i], preans = dp[i - 1];
        int ql = max(1, pre[i] - m), qr = min(mxn, pre[i] + m);
        dp[i] = min(preans, que(1, 1, mxn, ql, qr)) + 1;
        upd (1, 1, mxn, pre[i], dp[i]);
        preans = min (preans, dp[i]);
    }
    cout << dp[n] << endl;
}
posted @ 2024-11-22 19:30  lyrrr  阅读(3)  评论(0编辑  收藏  举报