zoukankan      html  css  js  c++  java
  • BZOJ 1597: [Usaco2008 Mar]土地购买 [斜率优化DP]

    1597: [Usaco2008 Mar]土地购买

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 4026  Solved: 1473
    [Submit][Status][Discuss]

    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块土地.

    Sample Output

    500

    HINT

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

    Source

    Gold


    首先,这个分组是任意分组

    矩形宽a长b,按先b后a的顺序排序,把那些可以包含的矩形去掉(就像离散化一样)

    然后剩下的b递减a递增

    f[i]=min(f[j]+a[j+1]*b[i])

    正好b是横坐标a是纵坐标

    斜率优化得到:

    j<k

    (f[j]-f[k])/(b[k+1]-b[j])<a[i]时k更优

    然后a和b都是单调的,用单调队列就行

    一点想法:

    本题b是单减的,但并不影响啊

    斜率并不一定非要规范的定义,方便用就行了

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    const int N=5e4+5,INF=1e9;
    typedef long long ll;
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
        return x*f;
    }
    int n;
    struct data{
        ll a,b;
        bool operator <(const data &r)const{return b==r.b?a>r.a:b>r.b;}
    }r[N];
    int q[N],head,tail;
    ll f[N];
    inline double slope(int x,int y){
        return (double)(f[x]-f[y])/(r[y+1].b-r[x+1].b);
    }
    void dp(){
        head=tail=1;
        for(int i=1;i<=n;i++){//printf("hi %d %d %d
    ",i,r[i].b,r[i].a);
            while(head<tail&&slope(q[head],q[head+1])<=r[i].a) head++;
            f[i]=f[q[head]]+r[q[head]+1].b*r[i].a;//printf("f %d
    ",f[i]);
            while(head<tail&&slope(q[tail],i)<slope(q[tail-1],q[tail])) tail--;
            q[++tail]=i; 
        }
        printf("%lld",f[n]);
    }
    int main(){
        //freopen("in.txt","r",stdin);
        n=read();
        for(int i=1;i<=n;i++) r[i].a=read(),r[i].b=read();
        sort(r+1,r+1+n);
        int p=0;r[++p]=r[1];
        for(int i=2;i<=n;i++)
            if(r[i].a>r[p].a) r[++p]=r[i]; 
        n=p;
        dp();
    }
  • 相关阅读:
    Github for Windows使用介绍
    Activity生命周期
    Java日期LocalDate使用
    一、安装Windows 2012域控(For SQLServer 2014 AlwaysOn)
    .NET(C#):分析IL中的if-else,while和for语句并用Emit实现
    sqlserver中几种典型的等待
    ServiceStack.Redis常用操作
    ServiceStack.Redis 之 IRedisTypedClient<第四篇>
    ServiceStack.Redis之IRedisClient<第三篇>
    Redis常用命令速查 <第二篇>
  • 原文地址:https://www.cnblogs.com/candy99/p/6259002.html
Copyright © 2011-2022 走看看