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 }

 

posted @ 2018-10-15 15:33  MJT12044  阅读(1213)  评论(0编辑  收藏  举报