题意:从一个序列中选出分成不交叉的m段 的最大和
解析 : 题目中 1 <= n <=1000000 所以二维数组是不能用了 所以 要想到简化为一维
dp[i][j]表示以i结尾的前i个数 分成j组的最大和 对于一个数A[i] 我们有两种选择,一是与第(i-1)个数在一组 或者 自成一组 ,所以状态方程就出来了
dp[i][j] = max(dp[i-1][j] + A[i], max(dp[k][j-1] {k| 1<= k <= i-1} ))
max(dp[k][j-1] {k| 1<= k <= i-1} 表示前i-1个数组成的j-1组的最大值
通过状态方程 我们可以发现 其实dp[i][j]的求解只和dp[*][j]与dp[*][j-1]有关所以本题只需要两个一维数组即可搞定状态转移。
#include <iostream> #include <cstring> #include <cmath> #include <algorithm> #include <cstdio> #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; const int maxn = 1000010,INF = 0xfffffff; int main() { int n,m; int A[maxn]; int pre[maxn]; int dp[maxn]; while(~scanf("%d%d",&m,&n)) { mem(pre,0); mem(dp,0); for(int i=1; i<=n; i++) scanf("%d",&A[i]); int maxx = -INF; for(int i=1; i<=m; ++i) { maxx = -INF; for(int j=i; j<=n; ++j) { dp[j] = max(dp[j-1], pre[j-1]) + A[j]; //用pre[j-1] 表示前j-1个数选出i-1组的和的最大值 因为每次我们是在更新dp[j]之后才更新pre[j-1] pre[j-1] = maxx; //在第i次更新dp[j] 时 pre[j-1] 用的仍然是 第i-1次时的值 这就保证了 pre[j-1] 表示的是 maxx = max(maxx,dp[j]); // 前i-1个数组成的j-1组的最大值 } } printf("%d\n",maxx); } return 0; }