1. 程式人生 > >【題解】CF#426(Div. 1) B.The Bakery

【題解】CF#426(Div. 1) B.The Bakery

oid name date amp 我們 bak pac build pri

  一個非常明顯的 \(nk\) dp 狀態 \(f[i][k]\) 表示以 \(i\) 為第 \(k\) 段的最後一個元素時所能獲得的最大代價。轉移的時候枚舉上一段的最後一個元素 \(j\)更新狀態即可。考慮如何優化這個過程?主要的時間消耗在兩個部分:一個是確定一段區間的貢獻,另一個是找到最大的值。

  這兩個都是可以使用線段樹來維護的,一段區間的貢獻我們可以掃描線,而最大值則直接線段樹維護最大值。如何滾動反而好像是最難的……想了一會兒,因為顯然 memset 不可接受,然而我們可以 \(O(n)\) 建樹啊……簡直對自己的zz無語惹~

#include <bits/stdc++.h>
using namespace std;
#define maxn 2000000
#define maxm 40000
int n, K, ans, a[maxn], rec[maxn], last[maxn];
int f[maxm][55];

int read()
{
    int x = 0, k = 1;
    char c; c = getchar();
    while(c < 0 || c > 9) { if(c == -) k = -1; c = getchar(); }
    
while(c >= 0 && c <= 9) x = x * 10 + c - 0, c = getchar(); return x * k; } struct Segament_Tree { int mx[maxn], mark[maxn]; void Push_Down(int p) { mark[p << 1] += mark[p], mark[p << 1 | 1] += mark[p]; mx[p << 1] += mark[p], mx[p << 1
| 1] += mark[p]; mark[p] = 0; } void Build(int p, int l, int r, int K) { if(l == r) { mark[p] = 0, mx[p] = f[l - 1][K]; return; } int mid = (l + r) >> 1; mark[p] = 0; Build(p << 1, l, mid, K), Build(p << 1 | 1, mid + 1, r, K); mx[p] = max(mx[p << 1], mx[p << 1 | 1]); } void Update(int p, int l, int r, int L, int R, int x) { if(L <= l && R >= r) { mx[p] += x, mark[p] += x; return; } if(L > r || R < l) return; int mid = (l + r) >> 1; Push_Down(p); Update(p << 1, l, mid, L, R, x); Update(p << 1 | 1, mid + 1, r, L, R, x); mx[p] = max(mx[p << 1], mx[p << 1 | 1]); } int Query(int p, int l, int r, int L, int R) { if(L <= l && R >= r) { return mx[p]; } if(L > r || R < l) return 0; int mid = (l + r) >> 1; Push_Down(p); return max(Query(p << 1, l, mid, L, R), Query(p << 1 | 1, mid + 1, r, L, R)); } }T[2]; int main() { n = read(), K = read(); for(int i = 1; i <= n; i ++) { a[i] = read(); last[i] = rec[a[i]], rec[a[i]] = i; } int now = 1, pre = 0; for(int j = 1; j <= K; j ++) { for(int i = 1; i <= n; i ++) { T[pre].Update(1, 1, n, last[i] + 1, i, 1); f[i][j] = T[pre].Query(1, 1, n, 1, i); } T[now].Build(1, 1, n, j); swap(now, pre); } printf("%d\n", f[n][K]); return 0; }

【題解】CF#426(Div. 1) B.The Bakery