• 【最大M子段和】dp + 滚动数组


    题目描述

    给定 n 个数求这 n 个数划分成互不相交的 m 段的最大 m 子段和。

    给出一段整数序列 A1,A2,A3,A4,...,Ax,...,An ,其中 1≤x≤n≤1,000,000, -32768≤Sx≤32767。

    我们定义一种函数 sum(i,j)=Ai + ... + Aj (1≤i≤j≤n,且Ai~Aj 是连续的数)。

    现在,我们得到一个正整数 m(1≤x≤m≤30),你的工作是寻找 m 对 i 与 j。这 m 对 i 和 j 满足以下条件:
      sum(i1,j1)+sum(i2,j2)+sum(i3,j3)+...+sum(im,jm)在这个序列中最大。
    注意:任意两区间[ix,jx]和[iy,jy]的交集均为空集。

    请你求出:最大的 sum(i1,j1)+sum(i2,j2)+sum(i3,j3)+...+sum(im,jm)是多少?

    输入格式

    第一行两个整数 n,m 。
    第二行由空格隔开的 n 个整数,即 A1~An 。

    输出格式

    请输出我们定义的:sum(i1,j1)+sum(i2,j2)+sum(i3,j3)+...+sum(im,jm)的最大值,即最大的 m 子段和。

    样例数据 1

    输入

    3 1 
    1 2 3

    输出

    6

    样例数据 2

    输入

    6 2 
    -1 4 -2 3 -2 3

    输出

    8

    题目分析

    形如“求将x,分成y份的最*值”问题,通常dp都为 f[j][i],表示将前j个元素分成i份的最*值。

    这道题也一样:f[j][i]如上所述,对于新加入的元素,有两种决策:

    1. 加到上一次的最后一段。
    2. 独立成段。

      转移方程就为:$f[j][i] = max(f[j - 1][i] + val[i], max_{k = 1}^{j - 1}{f[k][i - 1]} + val[i])$  

      稍微计算一下,会发现这样的空间已经报表。接下来就是滚动数组登场了。

      可以发现,转移方程中的j这一维总是从上一次的j-1转移,而i不变,而且f[j - 1][k]也只需要上一次的最大值即可,那么就可以使用滚动数组进行如下优化:

      1. 去掉i这一维, 并把i这一维提到外循环->保证j-1到j都是i这一维。 数组只需要f[N]

      2.用mx[j - 1]来表示$max_{k = 1}^{j - 1}{f[k][i - 1]} $, 每次内循环(j)更新, 以供下一个外循环(i)使用。

      于是转移变为:

    for(int i = 1; i <= m; i++){
            ll tmp = -oo;
            for(int j = i; j <= n; j++){
                f[j] = max(f[j - 1] + val[j], mx[j - 1] + val[j]);
                tmp = max(tmp, f[j - 1]);
                mx[j - 1] = tmp;
            }
        }

     code

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #include<cmath>
    using namespace std;
    
    const int N = 1e6 + 5, oo = 0x7fffffff;
    int n, m;
    typedef long long ll;
    ll f[N], mx[N], val[N];
    
    inline ll read(){
        ll i = 0, f = 1; char ch = getchar();
        for(; (ch < '0' || ch > '9') && ch != '-'; ch = getchar());
        if(ch == '-') f = -1, ch = getchar();
        for(; ch >= '0' && ch <= '9'; ch = getchar())
            i = (i << 3) + (i << 1) + (ch - '0');
        return i * f;
    }
    
    inline void wr(ll x){
        if(x < 0) putchar('-'), x = -x;
        if(x > 9) wr(x / 10);
        putchar(x%10+'0');
    }
    
    int main(){
        n = read(), m = read();
       memset(f, -127, sizeof f);
    for(int i = 1; i <= n; i++) val[i] = read(); for(int i = 1; i <= m; i++){ ll tmp = -oo; for(int j = i; j <= n; j++){ f[j] = max(f[j - 1] + val[j], mx[j - 1] + val[j]); tmp = max(tmp, f[j - 1]); mx[j - 1] = tmp; } } ll ans = -oo; for(int i = m; i <= n; i++) ans = max(ans, f[i]); wr(ans), putchar(' '); return 0; }
  • 相关阅读:
    有关Backgroundworker
    DataGridView风格设置
    Dev控件GridControl实现CheckBox列和ComBox列
    ALTER PROFILE DEFAULT LIMIT PASS_LIFE_TIME UNLIMITED
    PowerDesigner的Additional Checkes 中使用统配符
    PowerDesigner生成sql脚本时去掉双引号并把字段名设为大写
    PowerDesigner中的域(Domain)的概念及应用
    Oracle Sql中输入特殊字符 转义字符
    机械键盘 按一次字母有时候出来2个
    IE内嵌google chrome frame解决浏览器兼容问题
  • 原文地址:https://www.cnblogs.com/CzYoL/p/7253675.html
Copyright © 2020-2023  润新知