题目链接
给 n n n 个木材,求制造 k k k 个木板浪费的木材的最小值,木材可以随意组合
制造木板浪费的木材:将 m m m 块木材连在一起,将所有的木材砍成一样的高度,砍掉的就是浪费量
有分治优化,斜率优化, w q s wqs wqs 二分,我写的斜率优化 d p dp dp
先按高度从大到小排序
d p i , j dp_{i,j} dpi,j 表示前 i i i 个木材制成 k k k个木板的最小浪费量
s u m i sum_{i} sumi 表示前 i i i 个木材总面积
s u m w i sumw_{i} sumwi 表示前 i i i 个木材的宽度
d p i , j = d p k , j − 1 + s u m i − s u m k − h i ∗ ( s u m w i − s u m w k ) dp_{i,j} = dp_{k,j-1} + sum_{i} - sum_{k} - h_{i} * (sumw_{i} - sumw_{k}) dpi,j=dpk,j−1+sumi−sumk−hi∗(sumwi−sumwk)
由于 d p i , j dp_{i,j} dpi,j 只与 d p k , j − 1 dp_{k,j-1} dpk,j−1 有关,因此只用记前一个状态就行,设当前状态为 s t a t e state state,则前一个状态为 1 − s t a t e 1 - state 1−state
设 j < k < i j < k < i j<k<i 且 k k k 点比 j j j 点更优,易得
d p k , 1 − s t a t e + s u m i − s u m k − h i ∗ ( s u m w i − s u m w k ) < = d p j , 1 − s t a t e + s u m i − s u m j − h i ∗ ( s u m w i − s u m w j ) dp_{k,1-state} + sum_{i} - sum_{k} - h_{i} * (sumw_{i} - sumw_{k}) <= dp_{j,1-state} + sum_{i} - sum_{j} - h_{i} * (sumw_{i} - sumw_{j}) dpk,1−state+sumi−sumk−hi∗(sumwi−sumwk)<=dpj,1−state+sumi−sumj−hi∗(sumwi−sumwj)
即 d p k , 1 − s t a t e − s u m k + d p j , 1 − s t a t e − s u m j s u m w k − s u m w j < = − h i \frac{dp_{k,1-state} - sum_{k} + dp_{j,1-state} - sum_{j}}{sumw_{k} - sumw_{j}} <= - h_{i} sumwk−sumwjdpk,1−state−sumk+dpj,1−state−sumj<=−hi
设 y i = d p k , 1 − s t a t e − s u m k y_{i} = dp_{k,1-state} - sum_{k} yi=dpk,1−state−sumk, x i = s u m w k x_{i} = sumw_{k} xi=sumwk, y k − y j x k − x j < = − h i \frac{y_{k} -y_{j}}{x_{k} - x_{j}} <= - h_{i} xk−xjyk−yj<=−hi
说明如果 k k k 为解, j , k , i j,k,i j,k,i 应该是上凸的,则解集是下凸的,用一个单调队列维护解集
#include
#include
#include
#define mem(x,y) memset(x,y,sizeof x)
#define fo(i,s,t) for(int i=s;i<=t;i++)
#define cl1(x,y,n) fo(c1_i,0,n-1) x[c1_i]=y
#define cl2(x,y,n,m) fo(c2_i,0,n-1) fo(c2_j,0,m-1) x[c2_i][c2_j]=y
#define inf (~0U>>2)
#define inff (long long)(inf<<1)*(long long)(inf<<1)
using namespace std;
const int maxn=5e3+10;
const int maxm=2e3+10;
const int mod=1e9+7;
int n,k,q[maxn],state=1;
long long sum[maxn],sumw[maxn],dp[maxn][2];
struct node{long long w,h;}a[maxn];
bool cmp(node _x,node _y)
{
return _x.h>_y.h;
}
///dp[i][j]=dp[k][j-1]+sum[i]-sum[k]-a[i].h*(sumw[i]-sumw[k])
long long x(int i)
{
return sumw[i];
}
long long y(int i)
{
return dp[i][1-state]-sum[i];
}
double slope(int i,int j)
{
return (y(j)-y(i))*1.0/(x(j)-x(i));
}
int main()
{
scanf("%d%d",&n,&k);
fo(i,1,n) scanf("%lld%lld",&a[i].w,&a[i].h);
sort(a+1,a+n+1,cmp);
sum[0]=sumw[0]=0;
fo(i,1,n)
{
sum[i]=sum[i-1]+a[i].w*a[i].h;
sumw[i]=sumw[i-1]+a[i].w;
dp[i][1]=sum[i]-sumw[i]*a[i].h;
}
fo(j,2,k)
{
int l=1,r=1;
q[1]=0;
state=1-state;
fo(i,1,n)
{
/**不卡精度可以用这个
while(l=slope(q[r],i))
r--;
q[++r]=i;*/
while(l=__int128_t(y(i)-y(q[r]))*__int128_t(x(q[r])-x(q[r-1])))
r--;
q[++r]=i;
}
}
printf("%lld\n",dp[n][k%2]);
return 0;
}