2 1 1 100 100 1 2 2 1 100 100 1
10000 200题意:
给你n个矩形,长宽已知,求用不超过k个大矩形包含所有给定矩形,使得大矩形总面积和最小.
(1<=N<=50000,1<=K<=100,1 <= wi, hi <= 1000000)
思路:
首先按wi为主从大到小排序,hi为辅从大到小排序,如果后面的hi小于等于前面最大的hi,那么这个矩形肯定是可以被包含在前面已知的矩形中,换句话说,排好序之后的有用矩形一定是wi依次减小,hi依次增大
dp[k][i]表示到了第i个,使用了k个矩形的面积的最小值,
显然dp[k][i]=min(dp[k-1][j]+a[i].h*a[j+1].w),这是一个显然的斜率dp
转化为坐标轴,x=-a[j+1].w,y=dp[k-1][j],维护一下斜率便能轻松的解决。
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll dp[101][50010]; int q[50010]; struct node{ ll w,h; }a[50010],b[50010]; ll getDP(int i,int j,int k){ dp[j][i]=dp[j-1][k]+b[i].h*b[k+1].w; } ll getUP(int i,int j,int k){ return dp[k][i]-dp[k][j]; } ll getDOWN(int i,int j){ return b[j+1].w-b[i+1].w; } bool cmp(node x,node y){ if(x.w!=y.w) return x.w>y.w; return x.h>y.h; } int main(){ int n,k; while(scanf("%d%d",&n,&k)!=EOF){ for(int i=1;i<=n;i++) scanf("%lld%lld",&a[i].w,&a[i].h); int cnt=1; sort(a+1,a+n+1,cmp); b[cnt].w=a[1].w,b[cnt].h=a[1].h; ll maxv=a[1].h; for(int i=2;i<=n;i++){ if(a[i].h<=maxv) continue; cnt++; b[cnt].w=a[i].w,b[cnt].h=a[i].h; maxv=a[i].h; } for(int i=1;i<=cnt;i++) dp[1][i]=b[1].w*b[i].h; int head,tail; for(int i=2;i<=k;i++){ head=tail=0; q[tail++]=i-1; for(int j=i;j<=cnt;j++){ while(head+1<tail&&getUP(q[head+1],q[head],i-1)<=b[j].h*getDOWN(q[head+1],q[head])) head++; getDP(j,i,q[head]); while(head+1<tail&&getUP(j,q[tail-1],i-1)*getDOWN(q[tail-1],q[tail-2])<=getUP(q[tail-1],q[tail-2],i-1)*getDOWN(j,q[tail-1])) tail--; q[tail++]=j; } } ll ans=100000000000000000LL; for(int i=1;i<=k;i++) ans=min(ans,dp[i][cnt]); printf("%lld\n",ans); } return 0; }