zoukankan      html  css  js  c++  java
  • hdu-1024 Max Sum Plus Plus

    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 ≤ Sx ≤ 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(i2, 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. 

    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.
    
    这题好难啊,看了很久题解才看明白。 

    题意:给定n个数,从中选m串不重合的子串,求m串最大的子串和。

    解题思路:将问题分解为子问题,可从两个角度出发:
    从m的角度来看,当m等于1的时候,其实就是求最大连续子串和的题。
    从n的角度来看,每个数字无非就两种状态, 一是在上个串;二是新串的起始。
    这样思路就出来了:
    首先建立个dp[m][n]的数组。
    假设m=1时,我们遍历这n个数,每个数用dp数组记录:
    dp[1][i]=max(dp[1][i-1]+nu[i],0+nu[i])=max(dp[1][i-1],0)+nu[i];
    这样m=1时所有数的状态就出来了。
    那么当m=2呢,无非在m=1的基础上,看从哪里截取,好让最后的两个串和最大。
    但这里又牵扯到一点,我们依然从上面两个角度出发:
    从m的角度来看,m=2时,要截取两个串。两个串的位置是不定的,只要不重合就行,也就是说,
    如果要建第二个串,第一个串后面任何一个数都可以作为新串的开始,那该怎么确定呢? 这就
    要从n的角度来看,每个数两种状态,一是在上个串,二是新串的开始,如果这个数作为新串,
    那它的上个串一定是这个数前面所有数中dp[1][2]最大的,如果不作为新串,还要加这个数的
    话,就是直接dp[1][i]+nu[i];
    m=3……n,以此类推,可得最后的状态转移方程是:
    dp[i][j]=max(dp[i-1][j]+nu[i],max(dp[0][j-1]~dp[i-1][j-1])+nu[i]);
    但因为这题又卡内存,所以用这个二维数组过不了。又因为其实每一层的数只和该数前面的上一
    层的最大值有关,即只和max(dp[0][j-1]~dp[i-1][j-1])有关,所以用个记录最大值的数
    组mx[n]代替二维数组就行了。
    即最终的转移方程为:d[j]=max(d[j-1],pre[j-1])+num[j]; 附ac代码:
     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 using namespace std;
     5 const int M = 1111111;
     6 const int inf = 0x3f3f3f3f;
     7 int nu[M],dp[M],mx[M];
     8 int main(){
     9     int n,m,maxx;
    10     while(~scanf("%d %d",&m,&n)){
    11         memset(dp,0,sizeof(dp));
    12         memset(mx,0,sizeof(mx));
    13         for(int i=1;i<=n;i++){
    14             scanf("%d",&nu[i]);
    15         }
    16         for(int i=1;i<=m;i++){
    17             maxx=-inf;
    18             for(int j=i;j<=n;j++){
    19                 dp[j]=max(dp[j-1]+nu[j],mx[j-1]+nu[j]);
    20                 mx[j-1]=maxx;
    21                 maxx=max(maxx,dp[j]);
    22             }
    23         }
    24         printf("%d
    ",maxx);
    25     }
    26     return 0;
    27 }
    View Code
    
    
    
     

     

  • 相关阅读:
    URAL 2067 Friends and Berries (推理,数学)
    URAL 2070 Interesting Numbers (找规律)
    URAL 2073 Log Files (模拟)
    URAL 2069 Hard Rock (最短路)
    URAL 2068 Game of Nuts (博弈)
    URAL 2066 Simple Expression (水题,暴力)
    URAL 2065 Different Sums (找规律)
    UVa 1640 The Counting Problem (数学,区间计数)
    UVa 1630 Folding (区间DP)
    UVa 1629 Cake slicing (记忆化搜索)
  • 原文地址:https://www.cnblogs.com/zmin/p/7375321.html
Copyright © 2011-2022 走看看