1597: [Usaco2008 Mar]土地购买
Description
农夫John准备扩大他的农场,他正在考虑N (1 <= N <= 50,000) 块长方形的土地. 每块土地的长宽满足(1 <= 宽 <= 1,000,000; 1 <= 长 <= 1,000,000). 每块土地的价格是它的面积,但FJ可以同时购买多快土地. 这些土地的价格是它们最大的长乘以它们最大的宽, 但是土地的长宽不能交换. 如果FJ买一块3x5的地和一块5x3的地,则他需要付5x5=25. FJ希望买下所有的土地,但是他发现分组来买这些土地可以节省经费. 他需要你帮助他找到最小的经费.
Input
* 第1行: 一个数: N
* 第2..N+1行: 第i+1行包含两个数,分别为第i块土地的长和宽
Output
* 第一行: 最小的可行费用.
Sample Input
4
100 1
15 15
20 5
1 100
输入解释:
共有4块土地.
100 1
15 15
20 5
1 100
输入解释:
共有4块土地.
Sample Output
500
HINT
FJ分3组买这些土地: 第一组:100x1, 第二组1x100, 第三组20x5 和 15x15 plot. 每组的价格分别为100,100,300, 总共500.
第一次写GLOD。。。
做了两道题终于对斜率优化有了比较深刻的理解。。。虽然过程很艰难=,=
这道题首先很容易想到如果一块土地的长宽全部小于另一块,那么这块土地就没什么用处。。。
所以我首先排了下序,然后发现如果长(或宽)递增,去掉没有用的土地,剩下的土地的宽(或长)是递减的。。。
那么就可以发现这样的话,只需要确定一组土地的第一块和最后一块,那么中间的土地就不用管了。。。
因此得到转移方程:F[i]=min(F[j]+x[j+1]*y[i])
一般枚举i,j的话是O(n^2),这里的n是50000,会T。。。所以考虑优化。。。
如果决策点j比k优的话:
F[j]+x[j+1]*y[i]<F[k]+x[k+1]*y[i]
化简,得:y[i]*(x[j+1]-x[k+1])<F[k]-F[j]
很明显,是斜率优化。。。然后就可以做出来了。。。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cmath> 4 #include<cstring> 5 #include<cstdio> 6 #include<algorithm> 7 #include<string> 8 #include<map> 9 #include<queue> 10 #include<vector> 11 #include<set> 12 #define inf 1000000000 13 #define maxn 50000+5 14 #define maxm 10000+5 15 #define eps 1e-10 16 #define ll long long 17 #define for0(i,n) for(int i=0;i<=(n);i++) 18 #define for1(i,n) for(int i=1;i<=(n);i++) 19 #define for2(i,x,y) for(int i=(x);i<=(y);i++) 20 #define for3(i,x,y) for(int i=(x);i>=(y);i--) 21 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go) 22 using namespace std; 23 struct size{ 24 ll x,y; 25 }w[maxn]; 26 size a[maxn]; 27 ll f[maxn]; 28 int q[maxn]; 29 bool cmp(size a,size b){ 30 if(a.x==b.x) return a.y>b.y; 31 else return a.x>b.x; 32 } 33 int read(){ 34 int x=0,f=1;char ch=getchar(); 35 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 36 while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} 37 return x*f; 38 } 39 ll k(ll x,ll y){ 40 return a[y+1].x-a[x+1].x; 41 } 42 ll s(ll x,ll y){ 43 return f[x]-f[y]; 44 } 45 int main(){ 46 int n=read(); 47 for1(i,n){w[i].x=read();w[i].y=read();} 48 sort(w+1,w+n+1,cmp); 49 int tot=0; 50 for1(i,n){ 51 if(w[i].x<=a[tot].x&&w[i].y<=a[tot].y)continue; 52 a[++tot].x=w[i].x; 53 a[tot].y=w[i].y; 54 } 55 int l=0,r=0; 56 for1(i,tot){ 57 while(l<r&&a[i].y*k(q[l],q[l+1])<s(q[l],q[l+1]))l++; 58 f[i]=f[q[l]]+a[q[l]+1].x*a[i].y; 59 while(l<r&&k(i,q[r])*s(q[r],q[r-1])>k(q[r],q[r-1])*s(i,q[r]))r--; 60 q[++r]=i; 61 } 62 //for1(i,tot)cout<<f[i]<<endl; 63 cout<<f[tot]<<endl; 64 return 0; 65 }