【ybt高效进阶5-2-1】【luogu P1880】石子合并

石子合并

题目链接:ybt高效进阶5-2-1 / luogu P1880

题目大意

给你几堆石子排成一圈,每次选相邻的两堆合成一堆,费用是这新一堆石子的个数。
然后你要把它合到只有一堆,要你求最大费用最小费用。

思路

区间 DP 经典题。

就直接设 m i n n i , j minn_{i,j} minni,j 为把 i i i j j j 的区间合并的最小费用, m a x n i , j maxn_{i,j} maxni,j 则是最大费用。
然后就先枚举区间的长度,然后枚举区间,枚举分割的地方 DP 即可。
快速求合并费用可以用前缀和,复杂度为 O ( n 3 ) O(n^3) O(n3) 可过。

代码

#include<cstdio>
#include<iostream>
#define INF 0x3f3f3f3f3f3f3f3f

using namespace std;

int n, a[201], maxn[101][101], minn[101][101], sum[101];
int ansmaxn, ansminn;

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
		scanf("%d", &a[i]), sum[i] = sum[i - 1] + a[i], a[n + i] = a[i];
	for (int i = n + 1; i <= n + n; i++)//记得是环状的,所以求前缀和要复制一遍再处理
		sum[i] = sum[i - 1] + a[i];
	
	for (int j = 2; j <= n; j++)//先枚举合并的区间大小
		for (int st = 1; st <= n; st++) {
			int ed = st + j - 1;
			maxn[st][(ed <= n) ? ed : ed - n] = 0;
			minn[st][(ed <= n) ? ed : ed - n] = INF;
			for (int k = st; k < ed; k++) {
				maxn[st][(ed <= n) ? ed : ed - n] = max(maxn[st][(ed <= n) ? ed : ed - n], maxn[st][(k <= n) ? k : k - n] + maxn[(k + 1 <= n) ? k + 1 : k + 1 - n][(ed <= n) ? ed : ed - n] + sum[ed] - sum[st - 1]);
				minn[st][(ed <= n) ? ed : ed - n] = min(minn[st][(ed <= n) ? ed : ed - n], minn[st][(k <= n) ? k : k - n] + minn[(k + 1 <= n) ? k + 1 : k + 1 - n][(ed <= n) ? ed : ed - n] + sum[ed] - sum[st - 1]);
			}	
		}
	
	ansminn = INF;
	ansmaxn = 0;
	for (int i = 1; i <= n; i++) {//记得最后的环可能有很多种,所以要都枚举一次
		ansminn = min(ansminn, minn[i][(i + n - 1 <= n) ? i + n - 1 : i - 1]);
		ansmaxn = max(ansmaxn, maxn[i][(i + n - 1 <= n) ? i + n - 1 : i - 1]);
	}
	printf("%d\n%d", ansminn, ansmaxn);
	
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值