hdu 1024(不会) dp

传送门

把一个数组分成m个可不连续区间.求区间和最大值

-1 (4 ) -2 (3 -2 3) 分成2块 , max = 8;

思路:

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

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

                第一个状态表示前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]).
const int MAXN = 1e6 + 10;
const int inf = 0x3f3f3f3f;

int m,n;
ll dp[MAXN],pre[MAXN],a[MAXN];

int main(){
	//前 j 个数组分成 i 组 获得的最大值 
	//dp[i][j] = max(dp[i][j-1],dp[i-1][j-1]) + a[i];
	while(~scanf("%d%d",&m,&n)){
		memset(pre,0,sizeof(pre));
		memset(dp,0,sizeof(dp));
		for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
		
		ll ans;
		for(int i=1;i<=m;i++){
			ans = -inf;
			for(int j=i;j<=n;j++){
				dp[j]=max(dp[j-1],pre[j-1]) + a[j];
				pre[j-1] = ans;
				ans = max(ans,dp[j]);
			}
		}
		printf("%lld\n",ans);
	}
	return 0;
}
发布了20 篇原创文章 · 获赞 2 · 访问量 249

猜你喜欢

转载自blog.csdn.net/weixin_45535964/article/details/105486851
今日推荐