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
  • 相关阅读:
    Code Review
    关于calendar修改前的代码和修改后的代码
    程序员必备的代码审查(Code Review)清单
    一个数组中最大子数组的和并且加上测试用例
    阅读build to win的个人感想
    结对编码(柳祎、张许君)
    Review(patener)
    Review [myself]
    Impressions
    Array
  • 原文地址:https://www.cnblogs.com/galaxies/p/bzoj3675.html
Copyright © 2011-2022 走看看