首先,这道题是bzoj第120题,庆祝一下。
其实,并不是第一次见这道题了,之前在某高中oj上见过,当时数据很小(n<=2000),单纯的写了一个n^2logn的做法,不过貌似出了点问题,只得了20分,不过之后就没管了。
之后再见这道题,发现是一个比较简单的dp,O(n^2)的很好想,f[i]=min(f[j]+y[j+1]*x[i]), 但要注意的是,要先把没有用的土地除掉,不然会WA。
不过这样还是会超时,再发现,可以斜率优化,还是很好推的:(f[i]-f[j])/(y[j+1]-y[i+1])。之后就解决了
#include<bits/stdc++.h>
#define N 50000
using namespace std;
int n;
long long f[N+1];
int x[N+1],y[N+1],tot;
int q[N+1],l,r;
const long long inf=1e18;
struct oil{
int x;
int y;
bool operator < (const oil &A) const
{
if(x!=A.x)return x<A.x;
return y<A.y;
}
};oil A[N+1];
inline char nc()
{
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
int x=0,b=1;
char c=nc();
for(;!(c<='9'&&c>='0');c=nc())if(c=='-')b=-1;
for(;c<='9'&&c>='0';c=nc())x=x*10+c-'0';
return x*b;
}
inline void write(long long x)
{
if(x==0)putchar('0');
else
{
char buf[25];
int len=0;
if(x<0)putchar('-'),x=-x;
while(x)buf[++len]=x%10+'0',x/=10;
for(int i=len;i>=1;i--)putchar(buf[i]);
}
}
inline double slope(int i,int j)
{
return (double)(f[i]-f[j])/(y[j+1]-y[i+1]);
}
int main()
{
//freopen("in.txt","r",stdin);
n=read();
for(int i=1;i<=n;i++)
A[i].x=read(),A[i].y=read();
sort(A+1,A+n+1);
for(int i=1;i<=n;i++)
{
while(tot&&A[i].y>=y[tot])tot--;
x[++tot]=A[i].x,y[tot]=A[i].y;
}
// f[0]=0;
// for(int i=1;i<=tot;i++)
// {
// f[i]=inf;
// for(int j=0;j<i;j++)
// f[i]=min(f[i],f[j]+(long long)y[j+1]*x[i]);
// }
// cout<<f[tot];
f[0]=0,l=1,q[++r]=0;
for(int i=1;i<=tot;i++)
{
while(l<r&&slope(q[l+1],q[l])<=x[i])l++;
int tmp=q[l];
f[i]=f[tmp]+(long long)y[tmp+1]*x[i];
while(l<r&&slope(i,q[r])<slope(q[r],q[r-1]))r--;
q[++r]=i;
}
write(f[tot]);
return 0;
}
还是很快的。