bzoj1597 [Usaco2008 Mar]土地购买

Posted LLppdd

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj1597 [Usaco2008 Mar]土地购买相关的知识,希望对你有一定的参考价值。

[Usaco2008 Mar]土地购买

Time Limit: 10 Sec Memory Limit: 162 MB

Description

农夫John准备扩大他的农场,他正在考虑\(N (1 <= N <= 50,000)\)块长方形的土地. 每块土地的长宽满足\((1 <= 宽 < = 1,000,000; 1 <= 长 <= 1,000,000)\). 每块土地的价格是它的面积,但FJ可以同时购买多快土地. 这些土地的价
格是它们最大的长乘以它们最大的宽, 但是土地的长宽不能交换. 如果FJ买一块\(3*5\)的地和一块\(5*3\)的地,则他需要
\(5*5=25\). FJ希望买下所有的土地,但是他发现分组来买这些土地可以节省经费. 他需要你帮助他找到最小的经费.

Input

  • 第1行: 一个数:$ N$
  • \(2..N+1\)行: 第\(i+1\)行包含两个数,分别为第\(i\)块土地的长和宽

    Output

  • 第一行: 最小的可行费用.

    Sample Input

    4
    100 1
    15 15
    20 5
    1 100

    Sample Output

    500

    输入解释:

    共有4块土地.
    FJ分3组买这些土地:
    第一组:100x1,
    第二组1x100,
    第三组20x5 和 15x15 plot.
    每组的价格分别为100,100,300, 总共500.

显然有些田是白送的2333.。。。。(只要存在有别的田比这块田的长和宽都大,那么这块田直接白送。。。。。对吧)
然后把这些直接去掉。。。。
由于事先已经知道是斜率优化。。。(提示太明显了。。感觉刷专题就这一点不怎么好。。。)
我们就去凑那个式子
先按x从小到大排序。。。因为已经去掉了不用的土地,那么此时的y一定就是从大到小排的序
\(dp[i]\)表示买前\(i\)块土地的最优解,所以有了状态转移方程方程:
\(dp[i] = dp[j] + x[i] * y[j+1]\)
写成一次函数的形式:
\(-dp[j]=y[j+1]*x[i]-dp[i]\)
所以每一个点就是\((y[j+1],-dp[j])\)
\(k=x[i]\)满足单调性
当然这里就差不多了,但是由于上一篇我说的不是很清楚,我想再多说一句。。。
最开始排除的是两个点的斜率小于\(k\)的,其实是因为画图可以看出后面的点答案一定优于前面的。而当斜率大于k时,虽然当前的答案时前面的点更好(所以计算答案的时候就用的是第一个满足条件的点),但是由于\(k\)在单增,有可能\(k\)会超过它的斜率,所以蹦年确定。
而倒着删是因为如果不是个下凸包形状的话,那么中间那个点一定不是最优点,要么它前面的那个点是最优的,要么后面的是最优的。


#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e4 + 5;
struct lpl{
    long long x, y;
}lin, ini[maxn], field[maxn], point[maxn];
int n, tot, cnt, head, tail;
long long dp[maxn];

inline bool cmp(lpl a, lpl b)
{
    return a.x == b.x ? a.y < b.y : a.x < b.x;
}

inline void putit()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) scanf("%lld%lld", &ini[i].x, &ini[i].y);
}

inline double slop(lpl a, lpl b)
{
    return (double)(a.y - b.y) / (a.x - b.x);
}

inline void workk()
{
    sort(ini + 1, ini + n + 1, cmp);
    for(int i = 1; i <= n; i++){
        while(tot && ini[i].y >= field[tot].y) tot--;
        field[++tot] = ini[i];
    }
    point[head].x = field[1].y; point[head].y = 0;
    for(int i = 1; i <= tot; ++i){
        while(head < tail && slop(point[head], point[head + 1]) < field[i].x)   head++;
        dp[i] = (-point[head].y) + field[i].x * point[head].x;
        lin.x = field[i + 1].y, lin.y = (-dp[i]);
        while(head < tail && slop(point[tail], point[tail - 1]) > slop(point[tail], lin)) tail--;
        point[++tail] = lin;
    }
    cout << dp[tot];
}

int main()
{
    putit();
    workk();
    return 0;
}

以上是关于bzoj1597 [Usaco2008 Mar]土地购买的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 1597: [Usaco2008 Mar]土地购买

BZOJ 1597: [Usaco2008 Mar]土地购买 斜率优化

bzoj1597 [Usaco2008 Mar]土地购买

BZOJ 1597: [Usaco2008 Mar]土地购买斜率优化+凸包维护

bzoj 1597: [Usaco2008 Mar]土地购买

BZOJ1597: [Usaco2008 Mar]土地购买