zoukankan      html  css  js  c++  java
  • 最大m段子段和 Day9

    Now I think you have got an AC in Ignatius.L's "Max Sum" problem. To be a brave ACMer, we always challenge ourselves to more difficult problems. Now you are faced with a more difficult problem.

    Given a consecutive number sequence S 1, S 2, S 3, S 4 ... S x, ... S n (1 ≤ x ≤ n ≤ 1,000,000, -32768 ≤ S x ≤ 32767). We define a function sum(i, j) = S i + ... + S j (1 ≤ i ≤ j ≤ n).

    Now given an integer m (m > 0), your task is to find m pairs of i and j which make sum(i 1, j 1) + sum(i 2, j 2) + sum(i 3, j 3) + ... + sum(i m, j m) maximal (i x ≤ i y ≤ j x or i x ≤ j y ≤ j x is not allowed).

    But I`m lazy, I don't want to write a special-judge module, so you don't have to output m pairs of i and j, just output the maximal summation of sum(i x, j x)(1 ≤ x ≤ m) instead. ^_^

    InputEach test case will begin with two integers m and n, followed by n integers S 1, S 2, S 3 ... S n.
    Process to the end of file.
    OutputOutput the maximal summation described above in one line.
    Sample Input

    1 3 1 2 3
    2 6 -1 4 -2 3 -2 3

    Sample Output

    6
    8
    
    
            
     

    Hint

    Huge input, scanf and dynamic programming is recommended.

    思路:最大m段子段和问题,设sum[n][m]为前n个数,m段子段和的最大值,状态转移有三:
    1.a[n]不属于该第m段最大和,sum[n][m] = sum[n-1][m]
    2.a[n]属于该第m段最大和,且为新的一段 sum[n][m] = sum[n-1][m-1] + a[n]
    3.a[n]属于该第m段最大和,且不为新的一段 sum[n][m] = sum[n-1][m] + a[n]
    由状态转移方程易知,1与3互相矛盾,就要寻找第二个状态转移方程来辅助计算,令b[n][m]为包含a[n]的前n个数的m段最大子段和,则sum[n][m]为前n个数的m段最大子段和,a[n]不一定包含在内,据此知,sum[n][m] = max(b[j][m])(m<=j<=n),最终答案就是sum[n][m]
    由上述分析,可得出b[n][m]的状态转移方程,a[n]属于第m段/不属于第m段,即b[n][m] = max(b[n-1][m], sum[n-1][m-1]) + a[n],通过该式可以得出计算顺序,先计算b[n][m],其中需要sum[n-1][m-1]与b[n-1][m],再更新sum[n][m]),而在计算sum[n][m] = max(b[j][m])(n<=j<=m),类比完全背包的优化,在计算sum[n][m]时,sum[n][m] = max(b[j][m])(m<=j<=n) = max(b[n][m], sum[n-1][m]),因为sum[n-1][m] = max(b[x][m])(m<=x<=n-1),等式成立,我们枚举的顺序是从小到大,所以在sum[n][m]计算之前sum[n-1][m]已经计算好了,不需要再重复枚举了
    const int maxm = 1005;
    
    int sum[maxm][maxm], b[maxm][maxm], a[maxm];
    
    int main() {
        ios::sync_with_stdio(false), cin.tie(0);
        int n, m;
        int tmp;
        while(cin >> m >> n) {
            memset(sum, 0, sizeof(sum)), memset(a, 0, sizeof(a)), memset(b, 0, sizeof(b));
            for(int i = 1; i <= n; ++i) cin >> a[i];
            for(int i = 1; i <= m; ++i) {
                for(int j = i; j <= n; ++j) {
                    b[j][i] = max(b[j-1][i], sum[j-1][i-1]) + a[j];
                    sum[j][i] = max(sum[j-1][i], b[j][i]);
                }
            }
            cout << sum[n][m] << endl;
        }
        return 0;
    }
    但是注意,该题的范围是1e6,二维显然空间炸了,就需要优化为一维的滚动数组形式,我们将计算的式子都列出来:
    b[n][m] = max(b[n-1][m], sum[n-1][m-1]) + a[n], sum[n][m] = max(sum[n-1][m], b[n][m])
    滚动时从小到大,该位置为j,则j之前的是[][m],j之后的是[][m-1](上一轮的),则先计算b[],再更新sum[],因为sum和b有冲突,先sum[n-1][m-1],再sum[n-1][m],就用一个tmp来记录
    const int maxm = 1e6+5;
    
    int sum[maxm], b[maxm], a[maxm];
    
    int main() {
        ios::sync_with_stdio(false), cin.tie(0);
        int n, m;
        int tmp;
        while(cin >> m >> n) {
            memset(sum, 0, sizeof(sum)), memset(a, 0, sizeof(a)), memset(b, 0, sizeof(b));
            for(int i = 1; i <= n; ++i) cin >> a[i];
            for(int i = 1; i <= m; ++i) {
                tmp = -0x3f3f3f3f;
                for(int j = i; j <= n; ++j) {
                    b[j] = max(b[j-1], sum[j-1]) + a[j]; // 此处sum[j-1] 是第i-1段
                    sum[j-1] = tmp;  // 更新sum[j-1] 为第i段的, 该tmp是第i段的j-1,由上一次的循环继承而来
                    tmp = max(sum[j-1], b[j]); // 更新tmp, 该tmp是第i段的j,为下一次循环中的的j-1
                }
                sum[n] = tmp;
            }
            cout << sum[n] << "
    ";
        }
        return 0;
    }
    
    

     参考微博:https://www.cnblogs.com/chuckcpc/p/dp_Max_M_Sum.html

  • 相关阅读:
    BestCoder Round #29 1003 (hdu 5172) GTY's gay friends [线段树 判不同 预处理 好题]
    POJ 1182 食物链 [并查集 带权并查集 开拓思路]
    Codeforces Round #288 (Div. 2) E. Arthur and Brackets [dp 贪心]
    Codeforces Round #287 (Div. 2) E. Breaking Good [Dijkstra 最短路 优先队列]
    Codeforces Round #287 (Div. 2) D. The Maths Lecture [数位dp]
    NOJ1203 最多约数问题 [搜索 数论]
    poj1426
    POJ 1502 MPI Maelstrom [最短路 Dijkstra]
    POJ 2785 4 Values whose Sum is 0 [二分]
    浅析group by,having count()
  • 原文地址:https://www.cnblogs.com/GRedComeT/p/12237217.html
Copyright © 2011-2022 走看看