bzoj1597[Usaco2008 Mar] 土地购买
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1597
题目大意:
N (1 <= N <= 50,000) 块长方形的土地. 每块土地的长宽满足(1 <= 宽 <= 1,000,000; 1 <= 长 <= 1,000,000). 每块土地的价格是它的面积,可以同时购买多快土地. 这些土地的总价格是它们之中最大的长乘以它们之中最大的宽。
============================================
题解:
斜率优化
看到这种题肯定要先想到排序,而且我们很容易可以发现,如果有某个土地的长和宽都比另一土地的长和宽要小的话,那么这个土地的购买是相当于不需要花费的,即对答案没有贡献。那么我们将这样的土地删掉之后得到的土地序列,长是递增的,宽则是递减的。
(诶长宽什么的随便了就a跟b..)
于是容易得到方程:f[i]=f[j]+a[i]*b[j+1];
然后..就好了啊..什么-a[i]*b[j+1]+f[i]=f[j]移一下项
代码里mx[]存的是一开始的土地,nw[]是排完序删完的土地
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> typedef long long LL; using namespace std; #define maxn 51000 int q[maxn];LL f[maxn]; struct node {LL a,b;}mx[maxn],nw[maxn]; double Y(int j){return f[j];} double X(int j){return -nw[j+1].b;} double slop(int j1,int j2) { return (Y(j2)-Y(j1))/(X(j2)-X(j1)); } bool cmp(node x,node y) { if (x.a!=y.a) return x.a<y.a; return x.b<y.b; } int main() { int n,len,i,l,r; scanf("%d",&n); for (i=1;i<=n;i++) scanf("%lld%lld",&mx[i].a,&mx[i].b); sort(mx+1,mx+1+n,cmp); len=1;nw[1]=mx[1]; for (i=2;i<=n;i++) { while (len>0 && nw[len].b<=mx[i].b) len--; nw[++len]=mx[i]; } memset(f,0,sizeof(f)); l=1;r=1;q[1]=0; for (i=1;i<=len;i++) { while (l<r && slop(q[l],q[l+1])<nw[i].a) l++; int j=q[l]; f[i]=f[j]+nw[i].a*nw[j+1].b; while (l<r && slop(q[r-1],q[r])>slop(q[r],i)) r--; q[++r]=i; }printf("%lld\n",f[len]); return 0; }