Codeforces Round #426(Div.2)D题 DP+线段树

来源:互联网 发布:植物大战僵尸 for mac 编辑:程序博客网 时间:2024/06/16 03:10

题意:

题目链接:http://codeforces.com/contest/834/problem/D
给出n个数,分割成k个区间,每个区间的价值为该区间内不同数字的种类数,问分割之后,所有区间最大价值和是多少。


思路:

很容易得到方程:
dp[i][j]=max(dp[i-1][k]+kind(k+1,j)
其中dp[i][j]表示的是到第j个数为止已经分了i组的最大价值,k的变化范围是[i,j](想想就能明白),这方程要直接计算复杂度肯定不够。
这里需要用到线段树来优化,思考之后可以发现,当遍历到a[j]的时候,若a[j]上一次出现的位置是last[a[j]],那么a[j]会给起点为[last[a[j]] + 1,j],终点为j的每个区间都增加1的贡献,这一步可以利用线段树区间更新,若线段树上初始存的是i-1轮的dp结果,然后从左到右遍历的过程中每次将新的贡献更新到线段树上,就可以维护max(dp[i-1][k]+kind(k+1,j)
,直接query(i,j)即可得到dp[i][j]。
需要注意的地方是:每次更新贡献区间是[last[a[j]] + 1,j],但这贡献是属于last[a[j]到j-1的dp值,所以要更新的是[last[a[j]],j-1]。并且为了不让线段树区间从0开始,这里可以把last初值设置成1,对结果没有影响。


代码:

#include <bits/stdc++.h>using namespace std;#define lson l, m, rt << 1#define rson m + 1, r, rt << 1 | 1const int MAXN = 35005;int a[MAXN], dp[55][MAXN], last[MAXN];int maxx[MAXN << 2], lazy[MAXN << 2];void pushup(int rt) {    maxx[rt] = max(maxx[rt << 1], maxx[rt << 1 | 1]);}void pushdown(int rt, int len) {    if (lazy[rt]) {        lazy[rt << 1] += lazy[rt];        lazy[rt << 1 | 1] += lazy[rt];        maxx[rt << 1] += lazy[rt];        maxx[rt << 1 | 1] += lazy[rt];        lazy[rt] = 0;    }}void update(int s, int e, int z, int l, int r, int rt) {    if (s <= l && r <= e) {        maxx[rt] += z;        lazy[rt] += z;        return;    }    pushdown(rt, r - l + 1);    int m = (l + r) >> 1;    if (s <= m) update(s, e, z, lson);    if (e > m) update(s, e, z, rson);    pushup(rt);}int query(int s, int e, int l, int r, int rt) {    if (s <= l && r <= e)        return maxx[rt];    pushdown(rt, r - l + 1);    int m = (l + r) >> 1;    int ret = 0;    if (s <= m) ret = max(ret, query(s, e, lson));    if (e > m) ret = max(ret, query(s, e, rson));    return ret;}bool vis[MAXN];int main() {   // freopen("in.txt", "r", stdin);    int n, k;    scanf("%d%d", &n, &k);    for (int i = 1; i <= n; i++)        scanf("%d", &a[i]);    int kind = 0;    memset(vis, false, sizeof(vis));    for (int i = 1; i <= n; i++) {        if (!vis[a[i]]) ++kind;        dp[1][i] = kind;        vis[a[i]] = true;    }    for (int i = 2; i <= k; i++) {        memset(lazy, 0, sizeof(lazy));        memset(maxx, 0, sizeof(maxx));        for (int j = 1; j <= n; j++) {            update(j, j, dp[i - 1][j], 1, n, 1);            last[a[j]] = 1;        }        for (int j = 1; j < i; j++) last[a[j]] = j;        for (int j = i; j <= n; j++) {            //printf("(%d, %d)\n", last[a[j]] + 1, j);            update(last[a[j]], j - 1, 1, 1, n, 1);            dp[i][j] = query(i - 1, j - 1, 1, n, 1);            last[a[j]] = j;        }    }    printf("%d\n", dp[k][n]);    return 0;}
阅读全文
0 0
原创粉丝点击