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

16 篇文章 0 订阅
10 篇文章 0 订阅

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.

分析

这题列,明显是题斜率优化,一听逼格就很高对不对,其实很简单的。。怎么做呢?
首先很容易得到,若有两块土地长宽分别为l1,w1,l2,w2,若满足l1>=l2且w1>=w2则第二块土地可以忽略不计。
那么就先把所有没用的土地都去掉,并按长从小到大排序,那么宽自然就是递减的了。显然每次必然选取连续的一段,设f[i]表示前i块分成若干段的最小花费,显然可以得到f[i]=min(f[j]+w[j+1]∗l[i])
我们设有j < k且对于i而言选j比选k更优,那么必然有f[j]+w[j+1]∗l[i]

#include <bits/stdc++.h>

#define N 50005

#define ll long long
#define INF 0x3f3f3f3f

struct NOTE
{
    ll l,w;
}map[N];

ll f[N];
int Q[N];

ll read()
{
    ll k=1,x=0;
    char ch;
    ch=getchar();
    while(ch<'0' || ch>'9')
    {
        if(ch=='-')
            k=-1;
        ch=getchar();   
    }
    while(ch>='0' && ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*k;
}

bool camp(NOTE a,NOTE b)
{
    return a.l<b.l || a.l==b.l && a.w<b.w;
}

ll getl(int i,int j)
{
    return f[i]-f[j];
}

ll getr(int i,int j)
{
    return map[j+1].w-map[i+1].w;
}

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld%lld",&map[i].l,&map[i].w);
    }
    std::sort(map+1,map+n+1,camp);
    ll mx=0;
    int nn=n;
    for(int i=n;i>=1;i--)
    {
        if(map[i].w<=mx)
        {
            map[i].l=INF;
            nn--;
        }
        else mx=map[i].w;
    }
    std::sort(map+1,map+n+1,camp);
    n=nn;
    int head=1,tail=1;
    Q[1]=0;
    for(int i=1;i<=n;i++)
    {
        while(head<tail && getl(Q[head],Q[head+1])>=getr(Q[head],Q[head+1])*map[i].l)
            head++;
        f[i]=f[Q[head]]+(ll)map[i].l*map[Q[head]+1].w;
        while(head<tail && getl(Q[tail-1],Q[tail])*getr(Q[tail],i)>getl(Q[tail],i)*getr(Q[tail-1],Q[tail]));
            tail--;
        Q[++tail]=i;
    }
    std::cout<<f[n]<<std::endl;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值