CF 833 B. The Bakery
B. The Bakery
http://codeforces.com/contest/833/problem/B
题意:
将一个长度为n的序列分成k份,每份的cost为不同的数的个数,求最大cost的和。1≤n≤35000,1≤k≤50
分析:
dp[i][j]表示前i个数,分了j份。dp[i][k]=dp[j][k-1]+cost(j+1,i);cost(j+1,i)为这一段中不同数的个数。
然后考虑如何优化。发现每次增加一个位置,pre[i]~i-1区间的每个转移的位置的cost+1。然后每次转移是在上一个dp数组中取最大值,于是线段树维护。
代码:
1 /* 2 * @Author: mjt 3 * @Date: 2018-10-15 14:52:11 4 * @Last Modified by: mjt 5 * @Last Modified time: 2018-10-15 15:27:53 6 */ 7 #include<cstdio> 8 #include<algorithm> 9 #include<cstring> 10 #include<cmath> 11 #include<iostream> 12 #include<cctype> 13 #include<set> 14 #include<vector> 15 #include<queue> 16 #include<map> 17 #define fi(s) freopen(s,"r",stdin); 18 #define fo(s) freopen(s,"w",stdout); 19 using namespace std; 20 typedef long long LL; 21 22 inline int read() { 23 int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; 24 for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; 25 } 26 27 const int N = 35005; 28 29 int dp[N][55], pre[N], last[N], a[N]; 30 int n, k; 31 32 #define Root 1, n, 1 33 #define lson l, mid, rt << 1 34 #define rson mid + 1, r, rt << 1 | 1 35 struct SegmentTree { 36 int mx[N << 2], tag[N << 2], Cur; 37 inline void pushup(int rt) { mx[rt] = max(mx[rt << 1], mx[rt << 1 | 1]); } 38 inline void pushdown(int rt) { 39 if (tag[rt]) { 40 tag[rt << 1] += tag[rt]; mx[rt << 1] += tag[rt]; 41 tag[rt << 1 | 1] += tag[rt]; mx[rt << 1 | 1] += tag[rt]; 42 tag[rt] = 0; 43 } 44 } 45 void build(int l,int r,int rt) { 46 tag[rt] = 0; 47 if (l == r) { 48 mx[rt] = dp[l][Cur]; return ; 49 } 50 int mid = (l + r) >> 1; 51 build(lson); build(rson); 52 pushup(rt); 53 } 54 void update(int l,int r,int rt,int L,int R) { 55 if (L <= l && r <= R) { 56 mx[rt] ++; tag[rt] ++; 57 return ; 58 } 59 pushdown(rt); 60 int mid = (l + r) >> 1; 61 if (L <= mid) update(lson, L, R); 62 if (R > mid) update(rson, L, R); 63 pushup(rt); 64 } 65 int query(int l,int r,int rt,int L,int R) { 66 if (L <= l && r <= R) { 67 return mx[rt]; 68 } 69 pushdown(rt); 70 int mid = (l + r) >> 1, res = 0; 71 if (L <= mid) res = max(res, query(lson, L, R)); 72 if (R > mid) res = max(res, query(rson, L, R)); 73 return res; 74 } 75 }T; 76 77 void solve(int now) { 78 T.Cur = now - 1; T.build(Root); 79 for (int i=now; i<=n; ++i) { 80 T.update(Root, pre[i], i - 1); // 线段树维护的是dp[j][now-1]+cost(j+1,i)的值,所以pre[i]~i-1这个区间加1!!! 81 dp[i][now] = T.query(Root, 1, i - 1); 82 } 83 } 84 85 int main() { 86 n = read(), k = read(); 87 for (int cnt=0,i=1; i<=n; ++i) { 88 a[i] = read(); 89 pre[i] = last[a[i]]; last[a[i]] = i; 90 if (pre[i] == 0) cnt ++; 91 dp[i][1] = cnt; 92 } 93 for (int i=2; i<=k; ++i) solve(i); 94 cout << dp[n][k]; 95 return 0; 96 }