cf834D(dp+线段树区间最值,区间更新)

题目链接: http://codeforces.com/contest/834/problem/D

 

题意: 每个数字代表一种颜色, 一个区间的美丽度为其中颜色的种数, 给出一个有 n 个元素的数组, 问将其分成 k 个区间, 问 k 个区间的美丽度和最大为多少 .

 

思路: dp + 线段树区间更新, 区间最值

用 dp[i][j] 存储前 j 个元素分成 i 个区间的最大美丽度和为多少, 那么动态转移方程式为:

  dp[i][j] = max(dp[i - 1][k] + gel(k + 1, n)), 其中 i <= k <= n, gel(k + 1, n) 表示区间 [k + 1, n] 的美丽度为多少 .

可以用线段树来维护 dp[i -1][k] + gel(k + 1, n) 的值, 这部分和 http://www.cnblogs.com/geloutingyu/p/7298049.html 里面的线段树用法是一样的. 建树时将 sum 初始化为上一轮 dp 的结果. 再遍历 [i, m] 并将 dp 结果记录一下即可.

 

代码:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #define lson l, mid, rt << 1
 4 #define rson mid + 1, r, rt << 1 | 1
 5 using namespace std;
 6 
 7 const int MAXN = 4e4 + 10;
 8 int pre[MAXN], last[MAXN], a[MAXN];
 9 int dp[50 + 10][MAXN], sum[MAXN << 2], lazy[MAXN << 2];
10 
11 void push_up(int rt){
12     sum[rt] = max(sum[rt << 1], sum[rt << 1 | 1]);
13 }
14 
15 void push_down(int rt){
16     if(lazy[rt]){
17         sum[rt << 1] += lazy[rt];
18         sum[rt << 1 | 1] += lazy[rt];
19         lazy[rt << 1] += lazy[rt];
20         lazy[rt << 1 | 1] += lazy[rt];
21         lazy[rt] = 0;
22     }
23 }
24 
25 void build(int l, int r, int rt, int k){
26     lazy[rt] = 0;
27     if(l == r){
28         sum[rt] = dp[k][l - 1];//注意sum初始化为上一轮的dp结果,更新gel(l,m)时只能与dp[i-1][l-1]匹配,所以这里的l也要减一
29         return;
30     }
31     int mid = (l + r) >> 1;
32     build(lson, k);
33     build(rson, k);
34     push_up(rt);
35 }
36 
37 void update(int L, int R, int value, int l, int r, int rt){
38     if(L <= l && R >= r){
39         lazy[rt] += value;
40         sum[rt] += value;
41         return;
42     }
43     push_down(rt);
44     int mid = (l + r) >> 1;
45     if(L <= mid) update(L, R, value, lson);
46     if(R > mid) update(L, R, value, rson);
47     push_up(rt);
48 }
49 
50 int query(int L, int R, int l, int r, int rt){
51     if(L <= l && R >= r) return sum[rt];
52     push_down(rt);
53     int cnt = 0;
54     int mid = (l + r) >> 1;
55     if(L <= mid) cnt = max(cnt, query(L, R, lson));
56     if(R > mid) cnt = max(cnt, query(L, R, rson));
57     return cnt;
58 }
59 
60 int main(void){
61     int n, k;
62     scanf("%d%d", &n, &k);
63     for(int i = 1; i <= n; i++){
64         scanf("%d", &a[i]);
65         pre[i] = last[a[i]];
66         last[a[i]] = i;
67     }
68     for(int i = 1; i <= k; i++){
69         build(1, n, 1, i - 1);
70         for(int j = i; j <= n; j++){
71             update(pre[j] + 1, j, 1, 1, n, 1);
72             dp[i][j] = query(1, j, 1, n, 1);
73         }
74     }
75     printf("%d\n", dp[k][n]);
76     return 0;
77 }
View Code

 

posted @ 2017-08-09 15:09  geloutingyu  阅读(210)  评论(0编辑  收藏  举报