【队内赛 T3】【区间DP】大哥扛纵连

57 篇文章 0 订阅
这篇博客介绍了一道编程竞赛题目——大哥扛纵连,涉及动态规划算法的应用。博主给出了详细的解题思路,通过设置f[i][j]表示区间i到j的最小花费,并分析了当聚头的山在区间左右两侧时的费用计算方式,最终实现O(n^2)的时间复杂度求解。代码中展示了如何记录区间内的最高山并计算最小花费,以及如何在O(1)时间内查询结果。
摘要由CSDN通过智能技术生成

大哥扛纵连

队内赛 T3 大哥扛纵连


题目

在这里插入图片描述
在这里插入图片描述
输入输出样例
输入 #1

4 2
2 4 3 5
1 3
2 4

输出 #1

10
12

输入 #2

15 10
10 71 84 33 6 47 23 25 52 64 70 31 22 31 2
6 11
4 8
1 14
9 13
1 1
2 4
8 14
2 14
11 13
2 2

输出 #2

281
180
828
263
10
201
364
744
123
71

大样例 #3
example3.zip
在这里插入图片描述
为什么这个题目背景这么熟悉。


解题思路

设 f[i][j] 为 i 到 j 的山聚头的最小花费

在这里插入图片描述

如果聚头的山在最高山左边,那么T右边的山就需要花费 T_hight * (j -T + 1),T 左边的山花费 f[i][T - 1]
f[i][j] = f[i][T - 1] + T_hight * (j -T + 1)
如果聚头的山在 T 右边,f[i][j] = f[T + 1][j] + T_hight * (T - i + 1)
取个max就好了,最后 O(1) 查询 f[l][r] 就好了


Code

#include <bits/stdc++.h>

using namespace std;

struct DT{
	int i, s;
}mx[2010][2010];
int n, m, a[2100], f[2100][2100];

int main() {
	scanf("%d %d", &n, &m);
	for(int i = 1; i <= n; i ++)
		scanf("%d", &a[i]);
	for(int i = 1; i <= n; i ++) {
		mx[i][i].s = a[i], mx[i][i].i = i;
		for(int j = i + 1; j <= n; j ++)
			if(a[j] > mx[i][j - 1].s) {  //O(N ^ 2)记录 i 到 j 的最高山是哪座(T),高度是多少(T_hight)
				mx[i][j].s = a[j];
				mx[i][j].i = j;
			} else {
				mx[i][j].s = mx[i][j - 1].s;
				mx[i][j].i = mx[i][j - 1].i;
			}
	}
	for(int i = 1; i <= n; i ++)
		f[i][i] = a[i];  //自己跳自己也要距离😅
	for(int len = 2; len <= n; len ++)
		for(int i = 1; i <= n; i ++) {
			int j = i + len - 1, k = mx[i][j].i;
			f[i][j] = min(f[i][k - 1] + a[k] * (j - k + 1), f[k + 1][j] + a[k] * (k - i + 1));
		}
	for(int i = 1; i <= m; i ++) {
		int l, r;
		scanf("%d %d", &l, &r);
		printf("%d\n", f[l][r]);
	}
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值