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 }