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∗(max−min)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∗(7−6)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∗(10−9)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∗(7−7)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∗(2−1)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,r−1]合并,即
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][r−1][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;
}
坑点
离散化