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

Posted SSL_ZZL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了队内赛 T3区间DP大哥扛纵连相关的知识,希望对你有一定的参考价值。

大哥扛纵连

队内赛 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]);
	}
} 

以上是关于队内赛 T3区间DP大哥扛纵连的主要内容,如果未能解决你的问题,请参考以下文章

1024 (程序员节) 欢乐赛 T3 班服 (状压DP)

7.24校内交流赛T3qbxt复读警告

队内赛 T2数学巡回的梦魇之神喜欢数列

队内ACM赛

队内赛T1贪心日常

队内赛 T1数学暴力多项式滚出OI