Pangu and Stones(区间DP)

感受
还 是 挺 容 易 想 到 的 区 间 D P , 但 是 如 果 对 区 间 D P 理 解 不 透 彻 可 能 会 T L E 还是挺容易想到的区间DP,但是如果对区间DP理解不透彻\\可能会TLE DPDPTLE
思路
考 虑 连 续 区 间 合 并 , 而 且 费 用 最 少 , 推 断 是 区 间 D P 。 考虑连续区间合并,而且费用最少,推断是区间DP。 DP
考 虑 有 L 与 R 限 制 , 推 断 D P 状 态 是 3 维 的 。 设 d p [ l ] [ r ] [ k ] 表 示 区 间 [ l , r ] 合 并 后 剩 余 k 堆 的 最 小 值 考虑有L与R限制,推断DP状态是3维的。\\设dp[l][r][k]表示区间[l,r]合并后剩余k堆的最小值 LRDP3dp[l][r][k][l,r]k
考 虑 d p [ l ] [ r ] [ k ] 如 何 转 移 ? 考虑dp[l][r][k]如何转移? dp[l][r][k]
[ l , r ] 区 间 转 移 肯 定 是 区 间 [ l , m i d ] + [ m i d + 1 , r ] 区 间 转 移 [l,r]区间转移肯定是区间[l,mid]+[mid+1,r]区间转移 [l,r][l,mid]+[mid+1,r]
那 么 k 如 何 转 移 呢 ? 那么k如何转移呢? k
如 果 [ l , m i d ] 与 [ m i d + 1 , r ] 只 是 单 纯 拼 接 , 那 么 k 由 [ l , m i d ] 提 供 k − 1 , [ m i d + 1 , r ] 提 供 1 如果[l,mid]与[mid+1,r]只是单纯拼接,那么\\k由[l,mid]提供k-1,[mid+1,r]提供1 [l,mid][mid+1,r]k[l,mid]k1[mid+1,r]1
如 果 合 并 则 , k = 1 , 合 并 处 理 即 可 如果合并则,k=1,合并处理即可 k=1
因 此 d p 转 移 式 子 得 出 : 因此dp转移式子得出: dp
拼 接 : d p [ l ] [ r ] [ k + 1 ] = m i n ( d p [ l ] [ r ] [ k + 1 ] , d p [ l ] [ m i d ] [ k ] + d p [ m i d + 1 ] [ r ] [ 1 ] ) 拼接:dp[l][r][k+1]=min(dp[l][r][k+1], dp[l][mid][k]+dp[mid+1][r][1]) dp[l][r][k+1]=min(dp[l][r][k+1],dp[l][mid][k]+dp[mid+1][r][1])
合 并 : d p [ l ] [ r ] [ 1 ] = m i n ( d p [ l ] [ r ] [ 1 ] , d p [ l ] [ m i d ] [ k ] + d p [ m i d + 1 ] [ r ] [ 1 ] + s u m [ r ] − s u m [ l − 1 ] ) 其 中 s u m [ i ] 表 示 前 缀 和 合并:dp[l][r][1]=min(dp[l][r][1],dp[l][mid][k]+dp[mid+1][r][1]+sum[r]-sum[l-1])其中sum[i]表示前缀和 dp[l][r][1]=min(dp[l][r][1],dp[l][mid][k]+dp[mid+1][r][1]+sum[r]sum[l1])sum[i]

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const ll inf = 1e18;
const int maxn = 200;
int n, L, R;
ll sum[maxn];
ll dp[maxn][maxn][maxn];
void init(){
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= n; j++){
			for(int k = 1; k <= n; k++){
				dp[i][j][k] = inf;
			}
		}
		dp[i][i][1] = 0;
	}
}
void print(int len){
	for(int l = 1, r; ; l++){
		r = l + len - 1; if(r > n) break;
		for(int k = 1; k <= len; k++){
			printf("dp[%d][%d][%d] = %lld\n", l, r, k, dp[l][r][k]);
		}
	}
}
int main(){
	while(scanf("%d%d%d", &n, &L, &R) != EOF){
		init();
		ll v;
		for(int i = 1; i <= n; i++){
			scanf("%lld", &v); sum[i] = sum[i - 1] + v;
		}
		for(int len = 2; len <= n; len++){
			for(int l = 1, r; ; l++){
				r = l + len - 1; if(r > n) break;
				for(int mid = 1; mid < r; mid++){
					for(int k = 1; k < len; k++){
						dp[l][r][k + 1] = min(dp[l][r][k + 1], dp[l][mid][k] + dp[mid + 1][r][1]);
						if(k + 1 >= L && k + 1 <= R) dp[l][r][1] = min(dp[l][r][1], dp[l][mid][k] + dp[mid + 1][r][1] + sum[r] - sum[l - 1]);
					}///dp[l][mid][k] + dp[mid+1][r][1]合并
				}
			}
			//print(len);
		}
		if(dp[1][n][1] >= inf) puts("0");
		else printf("%lld\n", dp[1][n][1]);
	}
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值