题意:给你n个矩形,长宽已知,求用不超过k个大矩形包含所有给定矩形,使得大矩形总面积和最小
思路:dp[i][j]表示前i个用j个大矩形的最少面积 ,则dp[i][j]=Min(dp[k][j-1]+w[i]*h[k+1]) ,斜率维护。
代码:
#include<cstdio> #include<algorithm> using namespace std; typedef long long ll; const int N = 50005; int n,m, l,r; pair<int,int> a[N],s[N]; pair<int,ll> q[N]; int x,y; ll dp[2][N]; inline void push(int k,ll b){ while(l<r && (q[r].second-q[r-1].second)*(k - q[r].first)<=(b-q[r].second)*(q[r].first-q[r - 1].first)) r--; q[++r]=make_pair(k,b); } inline void pop(ll x){ while(l<r && (q[l].first - q[l+1].first)*x >= q[l+1].second - q[l].second) l++; } template <class T> inline bool rd(T &ret) { char c; int sgn; if(c = getchar() , c == EOF) return false; while(c != '-' && (c < '0' || c > '9')) c = getchar(); sgn = (c == '-') ? -1 : 1; ret = (c == '-') ? 0 : (c - '0'); while(c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0'); ret *= sgn; return true; } int main(){ while(~scanf("%d%d",&n,&m)){ for(int i=0;i<n;i++)rd(a[i].first),rd(a[i].second); sort(a,a+n); int cnt=1,mxb=a[n-1].second; s[0]=a[n-1]; for(int i=n-2;i>=0;i--)if(a[i].second>mxb){ mxb = a[i].second; s[cnt++]=a[i]; } n=cnt; ll mxa=s[0].first; for(int i=0;i<n;i++) dp[0][i]=mxa*s[i].second; ll ans=dp[0][n-1]; x=0; y=1; if(m>n) m=n; for(int k=1;k<m;k++){ l=0;r=-1; push(s[k].first,dp[x][k-1]); for(int i=k;i<n;i++){ pop(s[i].second); dp[y][i]=q[l].second+(ll)q[l].first*s[i].second; push(s[i+1].first,dp[x][i]); } x^=1; y^=1; if(dp[x][n-1]<ans) ans=dp[x][n-1]; else break; } printf("%lld\n",ans); } return 0; }