农夫John准备扩大他的农场,他正在考虑N (1 <= N <= 50,000) 块长方形的土地. 每块土地的长宽满足(1 <= 宽 <= 1,000,000; 1 <= 长 <= 1,000,000). 每块土地的价格是它的面积,但FJ可以同时购买多快土地. 这些土地的价格是它们最大的长乘以它们最大的宽, 但是土地的长宽不能交换. 如果FJ买一块3x5的地和一块5x3的地,则他需要付5x5=25. FJ希望买下所有的土地,但是他发现分组来买这些土地可以节省经费. 他需要你帮助他找到最小的经费.
题解:先排序一下去掉没用的矩形,然后就可以斜率优化啦。
f[i]=min(f[j]+b[j+1]*a[i])
f[j]+b[j+1]*a[i]<f[k]+b[k+1]*a[i]
$a[i] > frac{f[j]-f[k]}{b[k+1]-b[j+1]}$
#include<iostream> #include<cstdio> #include<algorithm> #define MN 50000 #define ll long long #define int long long using namespace std; inline int read() { int x = 0 , f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x * f; } int n,m; struct sq{int a,b;}s[MN+5],l[MN+5]; ll f[MN+5]; bool cmp(sq x,sq y){return x.a<y.a||(x.a==y.a&&x.b<y.b);} int q[MN+5],top,tail; double calc(int x,int y) { return (double)(f[x]-f[y])/(s[x+1].b-s[y+1].b); } int get(int x) { while(top>tail&&-x<calc(q[tail+1],q[tail])) tail++; return q[tail]; } void ins(int x) { while(top>tail&&calc(x,q[top])>calc(q[top],q[top-1]))--top; q[++top]=x; } main() { n=read(); for(int i=1;i<=n;i++)l[i].a=read(),l[i].b=read(); sort(l+1,l+n+1,cmp); for(int i=1;i<=n;i++) { while(m&&l[i].b>=s[m].b) --m; s[++m]=l[i]; } q[top=tail=1]=0;//f[1]=1LL*s[1].a*s[1].b; for(int i=1;i<=m;i++) { int from=get(s[i].a); f[i]=f[from]+1LL*s[from+1].b*s[i].a; ins(i); } cout<<f[m]; return 0; }