HDUOJ1024 Max Sum Plus Plus(详解)
题意:
给一个包含n个数的数组,从中选出m个没有交集的区间,使这m个区间的区间和的和最大,求出这个最大值
分析:
其实这个题n的范围如果不是那么大,能用二维dp写的话并不算难
但是n就是1e6那么大,即使m的范围比较小基本也只能写一维dp
for(i=1...m)
for(j=i...n)
dp[j]=max(dp[j−1]+a[j],best[j−1]+a[j])
注释中有详解
代码:
#include <bits/stdc++.h>
using namespace std;
const int inf = INT_MAX;
const int maxn = 1e6 + 10;
int m, n;
int a[maxn], dp[maxn], best[maxn];
int temp;
int main(int argc, char const *argv[])
{
while (~scanf("%d%d", &m, &n))
{
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
memset(dp, 0, sizeof dp);
memset(best, 0, sizeof best);
for (int i = 1; i <= m; ++i)
{
temp = -inf; //temp记录取出i个区间时各个区间和的最大值,所以每多取一个区间temp需要被置为-inf
for (int j = i; j <= n; ++j)
{
dp[j] = max(dp[j - 1] + a[j], best[j - 1] + a[j]); //dp[j]记录从前j个数中取出i个区间时各个区间和的最大值
best[j - 1] = temp; //best[j-1]记录从前j-1个数中取出i个区间时各个区间和的最大值,所以在temp被更新前更新
//这里是最难理解的,为什么是取出i个区间?那么dp[j]=best[j - 1] + a[j]岂不是可能表示从从前j个数中取出i+1个区间?
//蒟蒻的我曾想了一晚上...
//观察状态转移方程我们会发现,每一个dp[j]状态都包含了a[j]
//1.若temp<=dp[j-1]则temp被dp[j-1]更新,而best[j-1]又是被temp更新,则best[j-1]间接被dp[j-1]更新,所以best[j-1]状态包含a[j-1],a[j-1]和a[j]可以连成一个区间
//2.若temp>dp[j-1],temp不被dp[j-1]更新,best[j-1]间接被dp[j-2]更新,所以best[j-1]状态包含了a[j-2],此时需要一点思维理解能力了,
//并不是a[j]和a[j-2]隔空连接,而是a[j-1]的连接权被a[j]取代了
//此处有点类似用lower_bound和upper_bound找最长单调子序列长度,得到的数组并不一定是最长单调子序列,但数组的长度却是最长单调子序列的长度
//以上是我的理解,如有误还请指正!!!
temp = max(temp, dp[j]);
}
}
printf("%d\n", temp);
}
return 0;
}