zoukankan      html  css  js  c++  java
  • bzoj3675 [Apio2014]序列分割

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3675

    http://uoj.ac/problem/104

    【题解】

    当时想的时候猜了下从前往后分比较优。

    后来证明了一下怎么分都一样。。可以把贡献式子拆开来分析。

    这样分析完就可以得到贡献=Σ每两个块的和的积

    那么我们整理可以得到贡献=Σ第i个块的和*(前面所有块的和)

    那么有dp: f[i,j]表示到第i块,选择的数是a[1]...a[j]的贡献max。

    那么直接dp有50分。

    # include <stdio.h>
    # include <string.h>
    # include <algorithm>
    // # include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int M = 1e5 + 10, N = 210;
    const int mod = 1e9+7;
    
    # define RG register
    # define ST static
    
    int n, K, a[M];
    ll s[M], f[N][M];
    int pre[N][M];
    
    inline void prt(int i, int j) {
        if(i == 1) return;
        prt(i-1, pre[i][j]);
        printf("%d ", pre[i][j]);
    }
    
    int main() {
        scanf("%d%d", &n, &K);
        for (int i=1; i<=n; ++i) scanf("%d", &a[i]), s[i] = s[i-1] + a[i];
        for (int i=2; i<=K+1; ++i) 
            for (int j=1; j<=n; ++j) {
                f[i][j] = -1e18;
                for (int k=1; k<j; ++k) {
                    if(f[i][j] < f[i-1][k] + (s[j]-s[k])*s[k]) {
                        f[i][j] = f[i-1][k] + (s[j]-s[k])*s[k];
                        pre[i][j] = k;
                    }
                }
            }
        printf("%lld
    ", f[K+1][n]);
        prt(K+1, n);
        return 0;
    }
    View Code

    肯定不能直接dp,需要优化

    明显可斜率优化。

    直接上即可。

    uoj版本(输出方案,空间不限制)

    # include <stdio.h>
    # include <string.h>
    # include <algorithm>
    // # include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int M = 1e5 + 10, N = 210;
    const int mod = 1e9+7;
    
    # define RG register
    # define ST static
    
    int n, K, a[M];
    ll s[M], f[N][M];
    int pre[N][M];
    int q[M], head, tail;
    
    inline void prt(int i, int j) {
        if(i == 1) return;
        prt(i-1, pre[i][j]);
        printf("%d ", pre[i][j]);
    }
    
    inline ll slop(int i, int k1, int k2) {
        return f[i-1][k1]-f[i-1][k2]+s[k2]*s[k2]-s[k1]*s[k1];
    }
    
    inline ll getdp(int i, int j, int x) {
        return f[i-1][x]+(s[j]-s[x])*s[x];
    }
    
    int main() {
        scanf("%d%d", &n, &K);
        for (int i=1; i<=n; ++i) scanf("%d", &a[i]), s[i] = s[i-1] + a[i];
        for (int i=2; i<=K+1; ++i) {
            head = 1, tail = 0;
            for (int j=1; j<=n; ++j) {
                while(head<tail && slop(i, q[head], q[head+1]) <= (s[q[head+1]] - s[q[head]]) * s[j]) ++head;
                f[i][j] = getdp(i, j, q[head]);
                pre[i][j] = q[head];
                while(head<tail && slop(i, q[tail-1], q[tail]) * (s[j] - s[q[tail]]) >= slop(i, q[tail], j) * (s[q[tail]] - s[q[tail-1]])) --tail;
                q[++tail] = j;
            }
        }
        printf("%lld
    ", f[K+1][n]);
        prt(K+1, n);
        return 0;
    }
    View Code

    bzoj版本(不输出方案,空间限制)

    # include <stdio.h>
    # include <string.h>
    # include <algorithm>
    // # include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int M = 1e5 + 10, N = 210;
    const int mod = 1e9+7;
    
    # define RG register
    # define ST static
    
    int n, K, a[M];
    ll s[M], f[2][M];
    int q[M], head, tail;
    int pre, cur;
    
    inline ll slop(int k1, int k2) {
        return f[pre][k1]-f[pre][k2]+s[k2]*s[k2]-s[k1]*s[k1];
    }
    
    inline ll getdp(int j, int x) {
        return f[pre][x]+(s[j]-s[x])*s[x];
    }
    
    int main() {
        scanf("%d%d", &n, &K);
        for (int i=1; i<=n; ++i) scanf("%d", &a[i]), s[i] = s[i-1] + a[i];
        pre = 0, cur = 1;
        for (int i=2; i<=K+1; ++i) {
            head = 1, tail = 0;
            for (int j=1; j<=n; ++j) {
                while(head<tail && slop(q[head], q[head+1]) <= (s[q[head+1]] - s[q[head]]) * s[j]) ++head;
                f[cur][j] = getdp(j, q[head]);
                while(head<tail && slop(q[tail-1], q[tail]) * (s[j] - s[q[tail]]) >= slop(q[tail], j) * (s[q[tail]] - s[q[tail-1]])) --tail;
                q[++tail] = j;
            }
            swap(pre, cur);
        }
        printf("%lld
    ", f[pre][n]);
        return 0;
    }
    View Code
  • 相关阅读:
    API网络数据安全
    【值得收藏】一文掌握用户画像系统构建全流程
    手把手教你从0到1学会tensorflow进行模型训练,并能在网页轻松运行
    APP选择第三方消息推送平台时,有哪些需要关注的重要性能指标?
    如何防薅羊毛?个推基于大数据风控引擎助力APP反欺诈!
    微信为什么要搞一个小游戏?
    关于 JS 模块化的最佳实践总结
    张小龙2019微信公开课15个看点总结
    编程:从前有一个傻呆程序员,老婆交给他一项任务,他办了四次才满意
    JS是如何计算 1+1=2 的?
  • 原文地址:https://www.cnblogs.com/galaxies/p/bzoj3675.html
Copyright © 2011-2022 走看看