其实还是蛮好想得,只是。。。脑残把x写成nod然后debug半天最后还是看题解才找出来的qaq
我们按照长和宽作为一二关键字排序,然后可以很明显的发现如果nod[i-1].b<=nod[i].b那么i-1和i一起购买的话一定不会更差,所以清除所有的这些点以后就得到一个a单调增b单调减的序列,就不难得出状态方程
f[i]=min{f[j]+a[i]*b[j+1]}随随便便化简一下就会发下是裸的斜率dp了
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
int n,q[100020],tot;
LL f[50020];
struct node{
LL a,b;
bool operator<(const node& y)const {return a==y.a?b<y.b:a<y.a;}
}nod[50020],x[50020];
double Q(int a,int b){
return (double)(f[a]-f[b])/(x[b+1].b-x[a+1].b);
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%lld%lld",&nod[i].a,&nod[i].b);
sort(nod+1,nod+1+n);
for(int i=1;i<=n;i++){
while(tot&&nod[i].b>=x[tot].b)tot--;
x[++tot].a=nod[i].a,x[tot].b=nod[i].b;
}
int l=1,r=1;
for(int i=1;i<=tot;i++){
while(l<r&&Q(q[l+1],q[l])<x[i].a)l++;
f[i]=f[q[l]]+x[i].a*x[q[l]+1].b;
while(l<r&&Q(q[r-1],q[r])>=Q(q[r],i))r--;
q[++r]=i;
}
printf("%lld",f[tot]);
return 0;
}