zoukankan      html  css  js  c++  java
  • 【题解】CF#833 B-The Bakery

      一个非常明显的 (nk) dp 状态 (f[i][k]) 表示以 (i) 为第 (k) 段的最后一个元素时所能获得的最大代价。转移的时候枚举上一段的最后一个元素 (j)更新状态即可。考虑如何优化这个过程?主要的时间消耗在两个部分:一个是确定一段区间的贡献,另一个是找到最大的值。

      这两个都是可以使用线段树来维护的,一段区间的贡献我们可以扫描线,而最大值则直接线段树维护最大值。如何滚动反而好像是最难的……想了一会儿,因为显然 memset 不可接受,然而我们可以 (O(n)) 建树啊……简直对自己的zz无语惹~

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 2000000
    #define maxm 40000
    int n, K, ans, a[maxn], rec[maxn], last[maxn];
    int f[maxm][55];
    
    int read()
    {
        int x = 0, k = 1;
        char c; c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
    
    struct Segament_Tree
    {
        int mx[maxn], mark[maxn];
        
        void Push_Down(int p)
        {
            mark[p << 1] += mark[p], mark[p << 1 | 1] += mark[p];
            mx[p << 1] += mark[p], mx[p << 1 | 1] += mark[p];
            mark[p] = 0; 
        }
        
        void Build(int p, int l, int r, int K)
        {
            if(l == r) { mark[p] = 0, mx[p] = f[l - 1][K]; return; }
            int mid = (l + r) >> 1;
            mark[p] = 0; 
            Build(p << 1, l, mid, K), Build(p << 1 | 1, mid + 1, r, K);
            mx[p] = max(mx[p << 1], mx[p << 1 | 1]); 
        }
        
        void Update(int p, int l, int r, int L, int R, int x)
        {
            if(L <= l && R >= r) { mx[p] += x, mark[p] += x; return; }
            if(L > r || R < l) return;
            int mid = (l + r) >> 1;
            Push_Down(p);
            Update(p << 1, l, mid, L, R, x);
            Update(p << 1 | 1, mid + 1, r, L, R, x);
            mx[p] = max(mx[p << 1], mx[p << 1 | 1]);
        }
        
        int Query(int p, int l, int r, int L, int R)
        {
            if(L <= l && R >= r) { return mx[p]; }
            if(L > r || R < l) return 0;
            int mid = (l + r) >> 1;
            Push_Down(p);
            return max(Query(p << 1, l, mid, L, R), Query(p << 1 | 1, mid + 1, r, L, R));
        }
    }T[2];
    
    int main()
    {
        n = read(), K = read();
        for(int i = 1; i <= n; i ++)
        {
            a[i] = read();
            last[i] = rec[a[i]], rec[a[i]] = i;
        }
        int now = 1, pre = 0;
        for(int j = 1; j <= K; j ++)
        {
            for(int i = 1; i <= n; i ++)
            {
                T[pre].Update(1, 1, n, last[i] + 1, i, 1);
                f[i][j] = T[pre].Query(1, 1, n, 1, i);
            }
            T[now].Build(1, 1, n, j);
            swap(now, pre);
        }
        printf("%d
    ", f[n][K]);
        return 0;
    }
  • 相关阅读:
    02点睛Spring4.1-Java Config
    01点睛Spring4.1-依赖注入
    00点睛Spring4.1-环境搭建
    Cas(09)——通过Proxy访问其它Cas应用
    Cas(08)——单点登出
    Cas(07)——建立使用Cas进行单点登录的应用
    Cas(06)——基于数据库的认证
    Cas(05)——修改Cas Server的其它配置
    remove CMakeCache.txt and rerun cmake.On Debian/Ubuntu, package name is libncurses5-dev, on Redhat and derivates it is ncurses-devel.
    解放双手—Cobbler批量自动化部署多版本系统
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/9822942.html
Copyright © 2011-2022 走看看