题意:
n块矩形,问你合并成K块,切掉的面积最小是多少
思路1:斜率DP
首先按照高度从小到大排序
F[I][J]表示前i块矩形,划分成J块的最小代价。则
F[I][J]=min(F[I][J],F[K][J-1]+W(K+1,I))
W(i,j)表示把i到j这些合并一起的代价,sum[i]-sum[k]- h[k+1]*(sumw[i]-sumw[k]).
最后整理可得如下形式的斜率式:F[I]+A[I]*A[J]=F[J]+C[J](b+kx=y)
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=b;i>=a;i--)
using namespace std;
#define ll long long
ll rd()
{
ll x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
struct node{
ll w,h;
}p[50100],qq[50100];
ll sumw[50100],sum[50100];
const int N=50100;
int now,pre;
ll s[N],f[N][2],n,x,L,j,q[N],tail,head,k;
inline double X(ll i) {return p[i+1].h;}
inline double Y(ll i) {return f[i][pre]-sum[i]+p[i+1].h*sumw[i];}
inline double slope(ll i,ll j){return (Y(j)-Y(i))/(X(j)-X(i));}
bool cmp(node a,node b)
{
return a.h<b.h;
}
void init()
{
memset(sumw,0,sizeof(sumw));
memset(sum,0,sizeof(sum));
n=rd();k=rd();
rep(i,1,n)
{
ll x,y;
x=rd();y=rd();
qq[i]={x,y};
}
sort(qq+1,qq+1+n,cmp);
int tot=0;
rep(i,1,n)
if(qq[i].h==p[tot].h)
{
p[tot].w+=qq[i].w;
}
else{
tot++;
p[tot].w=qq[i].w;
p[tot].h=qq[i].h;
}
n=tot;
rep(i,1,n)
{
sumw[i]=sumw[i-1]+p[i].w;
}
rep(i,1,n)
{
sum[i]=sum[i-1]+p[i].w*p[i].h;
}
head=tail=1;q[1]=0;
}
int main()
{
memset(f,0,sizeof(f));
init();
now=0;pre=1;
rep(i,1,n) f[i][0]=1e18;
rep(o,1,k)
{
head=tail=1;q[1]=0;
//f[][0]=f[0][0]=0;
now=!now;pre=!pre;
rep(i,1,n)
{
while(head<tail && slope(q[head],q[head+1])<sumw[i]) head++;
//printf("%.3lf\n",slope(q[1],q[2]));
j=q[head];
//printf("j:=%d %d %d\n",j,tail,head);
f[i][now]=f[j][pre]+(sum[i]-sum[j])-p[j+1].h*sumw[i]+p[j+1].h*sumw[j];
//f[i]=f[j]+(s[i]-s[j]-L)*(s[i]-s[j]-L);
while(head<tail&& slope(q[tail-1],q[tail])>slope(q[tail],i)) tail--;
q[++tail]=i;
}
// rep(i,1,n) printf("%d ",f[i][now]);
// printf("\n");
}
printf("%lld\n",f[n][now]);
}
思路2:分治DP
打表可得,F[I]是从J转移过来的,F[i-1]是从K转移过来的,J始终>=K,则可用分治DP。
思路3:wqs带权二分(待补)