luogu P5336 [THUSC2016]成绩单

luogu P5336 [THUSC2016]成绩单

大意

就是给出一个序列 a [ 1... n ] a[1...n] a[1...n]还有 A A A B B B
每次从序列里抽出连续的一段,这一段的代价为
A + B ∗ ( m a x − m i n ) 2 A + B * (max - min) ^ 2 A+B(maxmin)2


下面给个样例解释:

A = 3 , B = 1 A = 3, B = 1 A=3,B=1

原序列为
7 10 9 10 6 7 10 7 1 2
首先把[5, 6]这个区间拿出来,代价为 A + B ∗ ( 7 − 6 ) 2 = 3 + 1 = 4 A + B * (7 - 6)^2 = 3 + 1 = 4 A+B(76)2=3+1=4
序列变为
7 10 9 10 10 7 1 2
然后再把[2,5]取出来,代价为 A + B ∗ ( 10 − 9 ) 2 = 3 + 1 = 4 A + B *(10-9)^2 = 3 + 1 = 4 A+B(109)2=3+1=4
序列变为
7 7 1 2
再把[1,2]取出来,代价为 A + B ∗ ( 7 − 7 ) 2 = 3 + 0 = 3 A + B *(7 - 7)^2 = 3 + 0 = 3 A+B(77)2=3+0=3
序列变为
1 2
最后把[1,2取出来,代价为 A + B ∗ ( 2 − 1 ) 2 = 3 + 1 = 4 A + B*(2 - 1)^2 = 3 + 1 = 4 A+B(21)2=3+1=4

最终代价和为 4 + 4 + 3 + 4 = 15 4 + 4 + 3 + 4 = 15 4+4+3+4=15


题解

一看就知道是区间dp
f [ l ] [ r ] [ x ] [ y ] f[l][r][x][y] f[l][r][x][y]表示区间 [ l , r ] [l,r] [l,r]没取走的当中最大的是 y y y,最小的是 x x x的最小代价
然后转移就很容易写了
分两种情况
1、 r r r [ l , r − 1 ] [l, r-1] [l,r1]合并,即 f [ l ] [ r ] [ m i n ( x , a [ r ] ) ] [ m a x ( y , a [ r ] ) = f [ l ] [ r − 1 ] [ x ] [ y ] f[l][r][min(x,a[r])][max(y,a[r]) = f[l][r-1][x][y] f[l][r][min(x,a[r])][max(y,a[r])=f[l][r1][x][y]
2、枚举一个k,然后分成两段
具体看代码吧:
code:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int f[55][55][55][55], g[55][55], a[55], b[55], n, A, B;
signed main(){
	memset(f, 0x3f, sizeof f), memset(g, 0x3f, sizeof g); 
	scanf("%lld", &n);
	scanf("%lld%lld", &A, &B);
	for(int i = 1; i <= n; i ++) scanf("%lld", &a[i]), b[i] = a[i];
	sort(b + 1, b + 1 + n);
	int m = unique(b + 1, b + 1 + n) - b - 1;
	for(int i = 1; i <= n; i ++) a[i] = lower_bound(b + 1, b + 1 + m, a[i]) - b, f[i][i][a[i]][a[i]] = 0, g[i][i] = A;//离散化
	for(int len = 1; len <= n; len ++){
		for(int l = 1; l + len - 1 <= n; l ++){
			int r = l + len - 1;
			for(int x = 1; x <= m; x ++)	
				for(int y = x; y <= m; y ++){
					f[l][r][min(x, a[r])][max(y, a[r])] = min(f[l][r][min(x, a[r])][max(y, a[r])], f[l][r - 1][x][y]);//转移1
					for(int k = l; k < r; k ++)
						f[l][r][x][y] = min(f[l][r][x][y], f[l][k][x][y] + g[k + 1][r]);//转移2
				}
			for(int x = 1; x <= m; x ++)	
				for(int y = x; y <= m; y ++)
					g[l][r] = min(g[l][r], f[l][r][x][y] + A + B * (b[y] - b[x]) * (b[y] - b[x]));//记录小代价
		}
	}
	printf("%lld", g[1][n]);
	return 0;
}

坑点

离散化

posted @ 2019-09-14 11:46  lahlah  阅读(26)  评论(0编辑  收藏  举报