【链接】
bzoj1597
【题目大意】
有 n 块土地,每块土地有长 r 和宽 c ,一次可以购买若干块土地,每次购买土地的代价是选择的土地的最大 r × 最大 c ,求买下所有土地的最小代价。
【解题报告】
首先可以想到对于一些土地可能存在一些包含关系,所以先去掉被包含的土地会更好考虑些(其实做了这些步骤后r就是降序的,而c是升序的)。其实此题可以看出是线性DP,定义 f[i]=min(f[i],f[j]−r[j+1]∗c[i])(j<i) ,但是好像n太大过不了,但因为满足以上条件,所以直接斜率优化即可。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=50005;
int n,tot,MAX,hed,til,que[maxn];
LL f[maxn];
struct wjd
{
int r,c;
bool operator < (const wjd &a) const{
return r>a.r;
}
}a[maxn];
inline int Read()
{
int res=0; char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9') res=res*10+ch-48,ch=getchar();
return res;
}
int X(int i,int j) {return a[i+1].r-a[j+1].r;}
LL Y(int i,int j) {return f[j]-f[i];}
int main()
{
freopen("1597.in","r",stdin);
freopen("1597.out","w",stdout);
n=Read(); tot=MAX=0;
for (int i=1; i<=n; i++) a[i]=(wjd){Read(),Read()};
sort(a+1,a+1+n);
for (int i=1; i<=n; i++)
if (a[i].c>MAX) MAX=a[i].c,a[++tot]=a[i];
hed=til=1; que[0]=que[1]=0;
for (int i=1; i<=tot; i++)
{
while (hed<til&&Y(que[hed],que[hed+1])<=(LL)a[i].c*X(que[hed],que[hed+1])) hed++;
f[i]=f[que[hed]]+(LL)a[que[hed]+1].r*a[i].c;
while (hed<til&&Y(que[til-1],que[til])*X(que[til],i)>=Y(que[til],i)*X(que[til-1],que[til])) til--;
que[++til]=i;
}
printf("%lld\n",f[tot]);
return 0;
}