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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM