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;
}