【bzoj1597- [Usaco2008 Mar]土地购买】斜率优化
【597】[Usaco2008 Mar]土地购买
【题目描述】
有N (1 <= N <= 50,000) 块长方形的土地. 每块土地的长宽满足(1 <= 宽 <= 1,000,000; 1 <= 长 <= 1,000,000). 每块土地的价格是它的面积,但FJ可以同时购买多快土地. 这些土地的价格是它们最大的长乘以它们最大的宽, 但是土地的长宽不能交换. 如果FJ买一块3×5的地和一块5×3的地,则他需要付5×5=25. FJ希望买下所有的土地,但是他发现分组来买这些土地可以节省经费. 他需要你帮助他找到最小的经费。
【输入格式】
第1行: 一个数: N
第2..N+1行: 第i+1行包含两个数,分别为第i块土地的长和宽。
【输出格式】
求最小的可行费用。
Sample Input
4
100 1
15 15
20 5
1 100
Sample Output
500
HINT
FJ分3组买这些土地: 第一组:100×1, 第二组1×100, 第三组20×5 和 15×15 plot. 每组的价格分别为100,100,300, 总共500
给定一些矩形,分组购买,一组的价格是其中最大的长*最大的宽。
n<=50000
一开始并没有思路。。。
首先,我们考虑没有贡献的矩形——对于x,如果存在a[y]>=a[x] && b[y]>=b[x],则x是无用的。排序去掉。
排序就先按x排序大到小,再按y排序大到小。
出现排序后x,y,z矩形,x能不能套y但能套z的话,那y也能套z,是不会错的。。
最后一定是a递减,b递增。
so:
f[i]=f[j]+a[j+1]*b[i]
然后用斜率优化。
这个是把除法改成乘法的。
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<cmath>
5 #include<iostream>
6 #include<algorithm>
7 #include<queue>
8 using namespace std;
9
10 typedef long long LL;
11 const int N=50010;
12 int n,pl,Q[N];
13 LL l=0,r=0,ai,xj,bj,j,f[N];
14 struct node{
15 LL a,b;
16 bool bk;
17 }p[N];
18
19 // f[i]=f[j]+a[j+1]*b[i]
20 // ai=b[i]
21 // xj=a[j+1]
22 // bj=f[j]
23
24 LL XX(int i,int j){return p[i+1].a-p[j+1].a;}
25 LL YY(int i,int j){return f[i]-f[j];}
26 double X(int i){return p[i+1].a;}
27 double Y(int i){return f[i];}
28 double find_k(int i,int j){return (Y(i)-Y(j))/(X(i)-X(j));}
29
30 bool cmp(node x,node y){
31 if(x.a!=y.a) return x.a>y.a;
32 return x.b>y.b;
33 }
34
35 bool judge_1()
36 {
37 LL tx=XX(Q[l],Q[l+1]),ty=YY(Q[l],Q[l+1]);
38 if(tx>=0) return ty>=((-ai)*tx);
39 return ty<=((-ai)*tx);
40 }
41
42 bool judge_2(int i)
43 {
44 LL t0=YY(Q[r],Q[r-1]),t1=XX(Q[r],Q[r-1]),t2=YY(i,Q[r]),t3=XX(i,Q[r]);
45 if(t1<0) t0=-t0,t1=-t1;
46 if(t3<0) t2=-t2,t3=-t3;
47 return (t0*t3)<(t1*t2);
48 }
49
50 int main()
51 {
52 freopen("a.in","r",stdin);
53 // freopen("acquire.in","r",stdin);
54 // freopen("acquire.out","w",stdout);
55 scanf("%d",&n);
56 for(int i=1;i<=n;i++)
57 {
58 scanf("%lld%lld",&p[i].a,&p[i].b);
59 p[i].bk=1;
60 }
61 sort(p+1,p+1+n,cmp);
62 j=1;
63 for(int i=2;i<=n;i++)
64 {
65 if(p[i].a<=p[j].a && p[i].b<=p[j].b) p[i].bk=0;
66 else j=i;
67 }
68 pl=1;
69 for(int i=2;i<=n;i++)
70 if(p[i].bk) p[++pl]=p[i];
71
72 for(int i=1;i<=pl;i++)
73 {
74 ai=p[i].b;
75 while(l<r && judge_1()) l++;/*find_k(Q[l],Q[l+1])>=(-ai)*/
76 j=Q[l];
77 xj=p[j+1].a;
78 bj=f[j];
79 f[i]=ai*xj+bj;
80 while(l<r && judge_2(i)) r--;/*find_k(Q[r],Q[r-1])<find_k(i,Q[r])*/
81 Q[++r]=i;
82 }
83 printf("%lld\n",f[pl]);
84 return 0;
85 }