Description
Kano准备扩大他的农场,眼下必须购买N块长方形土地。如果Kano买一块土地,价格就是土地的面积。他也可以选择并购一块土地,并购的价格为这些土地中最大的长乘以最大的宽,比如Kano购买3x5和5x3的土地,只需要支付5x5=25元,比分开买合算。
请你帮他计算购买所有土地的最小费用。Sample Input & Output
4
100 1
15 15
20 5
1 100500
啊啊,先膜一下“水”大犇。题目描述只是因为我把这题搬到自家oi上的。
在写本题的 O(n2) 暴力dp的时候有没有想过常数优化?毕竟那些长宽小于某一块土地的都对答案没啥贡献,可以算是附赠的。而且如果在一维有序的情况下只需要理论下限的 O(n) 复杂度就可以过掉了。 那么此题的转移就很显然了:将两者都倒序枚举,除去干扰单调性的数据,则长单调递减,宽单调递增。可以得到转移方程:
dp[n]=mink=0n−1{dp[k]+x[n]∗y[k+1]}
推出
g(i,j)
:
g(i,j)=dp[j]−dp[i]y[i+1]−y[j+1]
struct node{
int h,w;
bool operator < (const node &cmp)const{
if(h!=cmp.h)return h>cmp.h;
return w>cmp.w;
}
}Base[M],Q[M];
int qtop=0;
int deq[M],L=0,R=-1;
long long dp[M];
long long up(int x,int y){return dp[y]-dp[x];}
long long down(int x,int y){return Q[x+1].h-Q[y+1].h;}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d %d",&Base[i].h,&Base[i].w);
sort(Base+1,Base+n+1);
int w=0;
for(int i=1;i<=n;i++){
if(Base[i].w<=w)continue;
Q[++qtop]=Base[i];
w=Base[i].w;
}
n=qtop;
deq[++R]=0;
for(int i=1;i<=n;i++){
while(L<R&&up(deq[L],deq[L+1])<Q[i].w*down(deq[L],deq[L+1]))++L;
dp[i]=dp[deq[L]]+1LL*Q[deq[L]+1].h*Q[i].w;
while(L<R&&up(deq[R-1],deq[R])*down(deq[R],i)>up(deq[R],i)*down(deq[R-1],deq[R]))--R;
deq[++R]=i;
}
printf("%lld\n",dp[n]);
return 0;
}