码迷,mamicode.com
首页 > 其他好文 > 详细

Codeforces 833B 线段树优化 dp

时间:2017-08-01 23:04:53      阅读:618      评论:0      收藏:0      [点我收藏+]

标签:efi   max   ati   turn   class   div   优化   names   ems   

Codeforces  833B  The Bakery

题意: n 个数要分成 k 块,每块的价值是其不同数的个数,问价值和最大是多少。

tags: dp[i][j]表示前 j 个数分成 i 块的最大权值和,转移: dp[i][j] = max( dp[i-1][k] + val[k+1][j] ) , k是 1~j 。 但这个过程其实并不好转移,要利用累加的特点,用线段树进行优化 (感觉我不看题解是想不到的,2333)

大概就是,对于第 i 层,我们假定已经知道了第 i-1 层,也就是求出了 dp[i-1][j],现在要求dp[i][j]。遍历 j 从 1~n ,对于第 j 个数,假定 a[j] 上一个位置是 last[j],那我们对 last[j]+1 ~ j  位置都累加一个 1 。这样的话,dp[i-1][k] 就变成了 dp[i][j] ,然后求个区间最值就行了。

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define fi  first
#define se  second
typedef long long ll;
const int N = 35005, M = 55;

int n, k, a[N], last[N], pre[N];
ll  tr[N<<2], dp[M][N], lazy[N<<2];
void pushdown(int ro, int l, int r)
{
    if(l==r) return ;
    if(lazy[ro])
    {
        lazy[ro<<1] += lazy[ro];
        lazy[ro<<1|1] += lazy[ro];
        tr[ro<<1] += lazy[ro];
        tr[ro<<1|1] += lazy[ro];
        lazy[ro] = 0;
    }
}
void update(int ql, int qr, int ro, int l, int r, int c)
{
    if(ql<=l && r<=qr) {
        lazy[ro]+=c, tr[ro]+=c;
        return ;
    }
    pushdown(ro, l, r);
    int mid = l+r>>1;
    if(ql<=mid) update(ql, qr, ro<<1, l, mid, c);
    if(mid<qr) update(ql, qr, ro<<1|1, mid+1, r, c);
    tr[ro] = max(tr[ro<<1], tr[ro<<1|1]);
}
ll  query(int ql, int qr, int ro, int l, int r)
{
    if(ql<=l && r<=qr)  return tr[ro];
    pushdown(ro, l, r);
    ll  ans = 0;
    int mid = l+r>>1;
    if(ql<=mid) ans = max(ans, query(ql, qr, ro<<1, l, mid));
    if(mid<qr) ans = max(ans, query(ql, qr, ro<<1|1, mid+1, r));
    return ans;
}
void build(int ro, int l, int r, int i)
{
    lazy[ro] = 0, tr[ro] = 0;
    if(l==r) {
        tr[ro] = dp[i][l-1];
        return ;
    }
    int mid = l+r>>1;
    build(ro<<1, l, mid, i);
    build(ro<<1|1, mid+1, r, i);
    tr[ro] = max(tr[ro<<1], tr[ro<<1|1]);
}
int main()
{
    scanf("%d %d", &n, &k);
    rep(i,1,n) {
        scanf("%d", &a[i]);
        last[i] = pre[a[i]],  pre[a[i]] = i;
    }
    rep(i,1,k)
    {
        build(1, 1, n, i-1);
        rep(j,1,n)
        {
            update(last[j]+1, j, 1, 1, n, 1);
            dp[i][j] = query(1, j, 1, 1, n);
        }
    }
    printf("%lld\n", dp[k][n]);

    return 0;
}

Codeforces 833B 线段树优化 dp

标签:efi   max   ati   turn   class   div   优化   names   ems   

原文地址:http://www.cnblogs.com/sbfhy/p/7270698.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!