bzoj 4951: [Wf2017]Money for Nothing

1 篇文章 0 订阅

题意:给出n个生产者的开始生产时间和成本,和m个消费者的收购价格和收购截至时间,只能指定一个生产者和一个消费者,每天可以倒卖1个零件,问最大收益。
题解:分治
先把这题转换成一个几何问题:给出n个矩形的左下角和m个矩形的右上角,求最大矩形。设左下角点集为 L ,右上角为U再预处理一下,把那些不可能成为答案的点去掉,最终使得 Li.x<Li+1.x Li.y>Li+1.y U 也一样,只是去掉的点不同。具体看代码。然后设u(i)表示以 Li 为左下角的最大矩形的右上角的编号。 u(i) 是递增的,这里证明一下吧:
如图: u(A)=B ,所以 SOTUB>SCMNO ,假如 u(D)=C 那么就要满足 SCQPO>SSBOR ,这显然是不成立的。
所以,我们就可以分治来搞:每次我们处理左下角在 l1r1 之间,右上角在 l2r2 之间的最大值,设 md=(l1+r1)/2 ,递归下去找 l1md l2u(md) mdr1 u(md)r2 。这样总共 logn 层,每层总共遍历一次 U ,再加上预处理排序的nlogn,总复杂度就是 O((n+m)logn)
代码:

#include<bits/stdc++.h>
using namespace std;

int n,m;
struct pnt
{
    int x,y;
}a[500010],b[500010];

int cmp(pnt x,pnt y)
{
    return x.x==y.x?x.y<y.y:x.x<y.x;
}
int pre(pnt*a,int size,int type)
{
    sort(a,a+size,cmp);
    static bool del[500010];
    memset(del,0,sizeof(del));
    if(type==0)
    {
        int last=0;
        for(int i=1;i<size;i++)
        {
            if(a[i].y>=a[last].y)
            del[i]=1;
            else
            last=i;
        }
    }
    else
    {
        int last=size-1;
        for(int i=size-2;i>=0;i--)
        {
            if(a[i].y<=a[last].y)
            del[i]=1;
            else
            last=i;
        }
    }
    int nn=0;
    for(int i=0;i<size;i++)
    if(!del[i])
    a[nn++]=a[i];
    return nn;
}
long long get(int x,int y)
{
    if(b[y].x<a[x].x&&b[y].y<a[x].y)
    return 0;
    return (long long)(b[y].x-a[x].x)*(b[y].y-a[x].y);
}
long long wk(int l1,int r1,int l2,int r2)
{
    if(l1==r1)
    return 0;
    int md=l1+r1>>1,hh=l2;
    for(int i=l2+1;i<r2;i++)
    if(get(md,hh)<get(md,i))
    hh=i;
    return max(max(wk(l1,md,l2,hh+1),wk(md+1,r1,hh,r2)),get(md,hh));
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)
    {
        scanf("%d%d",&a[i].x,&a[i].y);
    }
    for(int i=0;i<m;i++)
    {
        scanf("%d%d",&b[i].x,&b[i].y);
    }
    n=pre(a,n,0);
    m=pre(b,m,1);/*
    puts("");
    for(int i=0;i<n;i++)
    printf("%d %d\n",a[i].x,a[i].y);
    puts("");
    for(int i=0;i<m;i++)
    printf("%d %d\n",b[i].x,b[i].y);
    for(int i=0;i<n;i++)
    {
        int hh=0;
        for(int j=0;j<m;j++)
        if(get(i,hh)<get(i,j))
        hh=j;
        printf("%d %d\n",i,hh);
    }*/
    printf("%lld",wk(0,n,0,m));
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值