题目链接:点我啊╭(╯^╰)╮
题目大意:
n
n
n 块
w
∗
h
w*h
w∗h 的木块,分成
k
k
k 组
每组木块全部切成当组木块的最低高度
求最少浪费面积
解题思路:
首先按高度从高到低排序
d
p
[
i
]
[
k
]
dp[i][k]
dp[i][k] 表示到第
i
i
i 块,分为
k
k
k 组的最大保留面积
答案即为
s
u
m
−
d
p
[
n
]
[
k
]
sum - dp[n][k]
sum−dp[n][k],设
p
r
e
pre
pre 为宽度前缀和
d
p
[
i
]
[
k
]
=
m
a
x
(
d
p
[
j
]
[
k
−
1
]
+
(
p
r
e
[
i
]
−
p
r
e
[
j
]
)
×
h
[
i
]
)
dp[i][k] = max(dp[j][k-1] + (pre[i] - pre[j]) \times h[i])
dp[i][k]=max(dp[j][k−1]+(pre[i]−pre[j])×h[i])
时间复杂度:
O
(
n
2
k
)
O(n^2k)
O(n2k)
考虑斜率优化,设
j
1
<
j
2
<
i
j_1<j_2<i
j1<j2<i
当
d
p
[
j
1
]
[
k
−
1
]
+
(
p
r
e
[
i
]
−
p
r
e
[
j
1
]
)
×
h
[
i
]
dp[j_1][k-1] + (pre[i] - pre[j_1]) \times h[i]
dp[j1][k−1]+(pre[i]−pre[j1])×h[i]
<
<
<
d
p
[
j
2
]
[
k
−
1
]
+
(
p
r
e
[
i
]
−
p
r
e
[
j
2
]
)
×
h
[
i
]
dp[j_2][k-1] + (pre[i] - pre[j_2]) \times h[i]
dp[j2][k−1]+(pre[i]−pre[j2])×h[i] 时
j
2
j_2
j2 比
j
1
j_1
j1 更优,则
j
1
j_1
j1 可以从决策集中删去
转化为 d p [ j 2 ] [ k − 1 ] − d p [ j 1 ] [ k − 1 ] p r e [ j 2 ] − p r e [ j 1 ] \frac{dp[j_2][k-1] - dp[j_1][k-1]}{pre[j_2]-pre[j_1]} pre[j2]−pre[j1]dp[j2][k−1]−dp[j1][k−1] > > > h [ i ] h[i] h[i]
符号为大于,维护上凸包,斜率递减,由于
h
[
i
]
h[i]
h[i] 递减,在队首操作
时间复杂度:
O
(
n
k
)
O(nk)
O(nk)
参考博客:暮冥
#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
using pii = pair <ll,int>;
const int maxn = 5e3 + 5;
int n, k, q[maxn];
ll sum, pre[maxn];
ll dp[maxn][2019];
struct node{
int w, h;
bool operator < (const node &A){
return h > A.h;
}
} a[maxn];
long double slope(int x, int y, int p){
long double t = dp[x][p-1] - dp[y][p-1];
return t / (pre[x] - pre[y]);
}
int main() {
scanf("%d%d", &n, &k);
for(int i=1; i<=n; i++) scanf("%d%d", &a[i].w, &a[i].h);
sort(a+1, a+n+1);
for(int i=1; i<=n; i++){
pre[i] = pre[i-1] + a[i].w;
sum += 1ll * a[i].h * a[i].w;
}
for(int p=1; p<=k; p++){
int l = 0, r = 0;
for(int i=1; i<=n; i++){
while(l<r && slope(q[l], q[l+1], p) >= a[i].h) l++;
dp[i][p] = dp[q[l]][p-1] + 1ll * (pre[i] - pre[q[l]]) * a[i].h;
while(l<r && slope(q[r], q[r-1], p) <= slope(q[r], i, p)) r--;
q[++r] = i;
}
}
printf("%lld\n", sum - dp[n][k]);
}