HDU1024 题解(DP)

HDU1024:

HDU1024 题解(DP)_第1张图片

题意: 把n个数分出m个区间,使得区间和最大。

思路:DP。状态:dp[i][j]表示把前j个数组分成i组的区间和。

                    转移方程:dp[i][j] = max(dp[i][j - 1], dp[i - 1][j - 1]) + a[j]; 其中: i - 1 <= k <= j - 1。

                    第一个状态表示前j - 1个数分成 i 组后将第 j 个数并入最后一个组

                    第二个状态表示前j - 1个数分成 i - 1 组之后第 j 个数单独成一组

                    因为二维dp会炸,需要优化:

                    可以发现dp[i - 1][j - 1]可以用一个pre数组记录, 则转移方程可以写成:

                    dp[i][j] = max(dp[i][j - 1], pre[j - 1]) + a[j];

                    此时又可以发现dp数组的第一维是对结果没有影响的,再改写转移方程为:

                    dp[j] = max(dp[[j - 1], pre[j - 1] + a[j];

                    而pre数组的更新则是:

                    pre[j - 1] = max(pre[j - 2], dp[j]).

AC代码:

#include
#include
#include
#include
using namespace std;

const int maxn = 1e6;
const int inf = 0x3f3f3f3f;

long long dp[maxn + 5];
long long a[maxn +5];
long long pre[maxn + 5];
int n, m;

int main(){
	while(~scanf("%d %d", &m, &n)){	
		memset(dp, 0, sizeof(dp));
		memset(pre, 0, sizeof(pre));
		for(int i = 1; i <= n; i++){
			scanf(" %lld", &a[i]);
		}
		long long tmp;
		for(int i = 1; i <= m; i++){
			tmp = -inf;
			for(int j = i; j <= n; j++){
				dp[j] = max(dp[j - 1], pre[j - 1]) + a[j];
				pre[j - 1] = tmp;
				tmp = max(tmp, dp[j]);
			}
		}
		printf("%lld\n", tmp);
	}
	return 0;
}

tmp最终记录的就是前 m 到 n 个数分成 i 组的区间和最大值,即答案。

不开LL会WA。

你可能感兴趣的:(题解)