luoguP2418 yyy loves OI IV
阿新 • • 發佈:2018-09-08
ems else 一個人 mem include ons bit namespace ++
https://www.luogu.org/problemnew/show/P2418
暴力 DP 做這題只有 30 分
考慮用線段樹優化這個 DP
先處理一下整個房間都膜拜一個人的情況,然後將 1 的當成 -1, 2 當成 1,處理前綴和,可以發現對於前綴和為 x 的情況,只能從前綴和為 [x - k, x + k] 的地方轉移過來,用線段樹維護 DP 數組的最小值就行了
#include <bits/stdc++.h> using namespace std; const int N = 500000 + 10; int minn[N << 3], a[N], s[N], f[N]; int n, k, last; void change(int u, int l, int r, int x, int y) { minn[u] = min(minn[u], y); if(l == r) return; int mid = (l + r) >> 1; if(mid >= x) change(u << 1, l, mid, x, y); else change(u << 1 | 1, mid + 1, r, x, y); } int Q; void query(int u, int l, int r, int L, int R) { if(l <= L && R <= r) { Q = min(Q, minn[u]); return; } int mid = (L + R) >> 1; if(mid >= l) query(u << 1, l, r, L, mid); if(mid + 1 <= r) query(u << 1 | 1, l, r, mid + 1, R); } int main() { memset(minn, 0x3f, sizeof(minn)); cin >> n >> k; s[0] = N; for(int i = 1; i <= n; i++) { int t; scanf("%d", &t); if(t == 1) a[i] = -1; else a[i] = 1; s[i] = s[i - 1] + a[i]; } change(1, 1, n + k + N, N, 0); for(int i = 1; i <= n; i++) { if(a[i] != a[i - 1]) last = f[i - 1]; else last = min(last, f[i - 1]); f[i] = last + 1; Q = INT_MAX; query(1, s[i] - k, s[i] + k, 1, n + k + N); f[i] = min(f[i], Q + 1); change(1, 1, n + k + N, s[i], f[i]); } cout << f[n] << endl; return 0; }
luoguP2418 yyy loves OI IV