【luogu1578】奶牛浴场 [动规]

[luogu1578]奶牛浴场

按照论文上第一种算法 时间复杂度:\(O(S^2)\) 空间复杂度:\(O(S)\)
算法二的话需要离散化处理一下面积

(from 王知昆dalao的PPT)

现在矩形四个角上各加一个障碍点

第一次取1号点作为所要枚举的极大子矩形的左边界

设定上下边界为矩形的上下边界

从左向右扫描,第一次遇到2号点,可以得到一个有效的极大子矩形:1591261-20190819160052086-1907315531.png

因为左边界覆盖1号点且右边界在2号点右边的有效子矩形都不能包含2号点,所以需要修改上下边界 2号点在1号点上方,因此要修改上边界

继续扫描到3号点,又得到一个极大有效子矩形:1591261-20190819160349962-778678938.png因为三号点在一号点下方 因此修改下界

以此类推,可以得到所有以1号点为左边界的极大有效子矩形。
然后将左边界移动到2号点、3号点……横坐标的位置。开始扫描以2号点、3号点……为左边界的极大子矩形。

前面的做法可以找出所有左边界覆盖了一个障碍点的极大子矩形,此外,还有两类遗漏的情况

一类是左边界与整个矩形的左边界重合,右边界覆盖一个障碍点的情况。
解决方法:用类似的方法从右向左扫描一次
1591261-20190819160727374-516486728.png
另一类是左边界与整个矩形的左边界重合,且右边界也与整个矩形的右边界重合的情况。
解决方法:预处理时增加特殊判断。
1591261-20190819160809799-1748782999.png

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rg register
#define Max(x,y) ((x)>(y)?(x):(y))
#define Min(x,y) ((x)>(y)?(y):(x))
const int N=30000+10,M=2e5+5,inf=0x3f3f3f3f,P=19650827;
int l,w,n,best;
template <class t>void rd(t &x){
    x=0;int w=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=w?-x:x;
}

struct node{
    int x,y;
    bool operator<(const node&A)const{
        return x==A.x?y<A.y:x<A.x;
    }
}a[N];
bool cmp(node A,node B){return A.y<B.y;}
int main(){
    freopen("in2.txt","r",stdin);
    //freopen("xor.out","w",stdout);
    rd(l),rd(w),rd(n);
    for(int i=1;i<=n;++i) rd(a[i].x),rd(a[i].y);
    a[++n].x=l,a[n].y=0,a[++n].x=0,a[n].y=w,
    a[++n].x=0,a[n].y=0,a[++n].x=l,a[n].y=w;
    sort(a+1,a+n+1);
    for(int i=1;i<=n;++i){
        int high=w,low=0,maxl=l-a[i].x;
        for(int j=i+1;j<=n;++j){
            if(maxl*(high-low)<=best) break;
            best=Max(best,(a[j].x-a[i].x)*(high-low));
            if(a[i].y==a[j].y) break;
            else if(a[j].y>a[i].y) high=Min(high,a[j].y);
            else low=Max(low,a[j].y);
        }
        high=w,low=0,maxl=a[i].x;
        for(int j=i-1;j;--j){
            if(a[j].y<=high&&a[j].y>=low){
                if(maxl*(high-low)<=best) break;
                best=Max(best,(a[i].x-a[j].x)*(high-low));
                if(a[i].y==a[j].y) break;
                else if(a[j].y>a[i].y) high=Min(high,a[j].y);
                else low=Max(low,a[j].y);
            }
        }
    }
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<n;++i) best=Max(best,(a[i+1].y-a[i].y)*l);
    printf("%d",best);
    return 0;
}

转载于:https://www.cnblogs.com/lxyyyy/p/11377767.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值