zoukankan      html  css  js  c++  java
  • Codeforces 833B 线段树优化 dp

    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
    ", dp[k][n]);
    
        return 0;
    }
  • 相关阅读:
    投稿007期|令人震惊到发指的PyObject对象代码设计之美
    使用OpenCV通过摄像头捕获实时视频并探测人脸
    洛谷 P1259【黑白棋子的移动】
    入门OJ 1281【营救(save)】
    入门OJ 3204【射击】
    POJ 3126【长度为素数的路径个数】
    POJ 1980【Unit Fraction Partition】
    洛谷 P2374【搬运工】
    【常用算法总结——记忆化搜索】
    P3052 [USACO12MAR]【摩天大楼里的奶牛(Cows in a Skyscraper)】
  • 原文地址:https://www.cnblogs.com/sbfhy/p/7270698.html
Copyright © 2011-2022 走看看