首页 > 其他分享 >洛谷P1578 奶牛浴场

洛谷P1578 奶牛浴场

时间:2023-06-16 19:01:27浏览次数:40  
标签:P1578 障碍 浴场 边界 枚举 ans 洛谷 矩形 号点

题目大意

又是农夫约翰

有一个 $ L \times W$ 的矩阵,中间有 $ n $ 个障碍,你要框出面积最大的一块长方形,其中不能包含障碍。

数据范围

对于所有数据, \(0 \le n \le 5 \times 10^3,1 \le L,W \le 3 \times 10^4\)


题解

首先,可以根据极大化思想设计一个基本算法:

枚举上下左右四个边界,然后判断组成的矩形是否是有效子矩形。

时间复杂度:$ O \left( S ^ 5\right)$

初步改进算法

算法:枚举左右边界,然后对处在边界内的点排序。

每两个相邻的点和左右边界一起组成一 个矩形。

复杂度: $ O \left( S ^ 3\right)$

可以改进的地方:枚举了部分不是极大子矩形的情况

进一步改进算法

从下面 2 个方面去考虑:

  1. 保证每一个枚举的子矩形都是有效的
  2. 保证每一个枚举的子矩形都是极大的

算法的过程

枚举极大子矩形的左边界

\(\to\) 根据确定的左边界,找出相关的极大子矩形

$ \to $ 检查和处理遗漏的情况

首先,将所有障碍点按横坐标从小到大的顺序将点标为 \(1\) 号点,\(2\) 号点……

为了处理方便,在矩形的四个顶点上各增加 \(1\) 个障碍点。

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

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

最大子矩形1

从左向右扫描,第一次遇到 \(2\) 号点,可以得到一个有效的极大子矩形

最大子矩形2

因为左边界覆盖 1 号点且右边界在 2 号点右边的有效子矩形都不能包含 2 号点,

所以需要修改上下边界,2 号点在 1 号点上方,因此要修改上边界

继续扫描到 \(3\) 号点,又得到一个极大有效子矩形,如图所示

最大子矩形3

因为 \(3\) 号点在 \(1\) 号点下方,所以要修改下边界。

然后将左边界移动到 \(2\) 号点、\(3\) 号点……横坐标的位置。

开始扫描以 \(2\) 号点、\(3\) 号点……为左 边界的极大子矩形。

遗漏的情况

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

第一类

左边界与整个矩形的左边界重合,右边界覆盖一个障碍点的情况。

解决方法

用类似的方法从右向左扫描一次。

第二类

是左边界与整个矩形的左边界重合,且右边界也与整个矩形的右边界重合的情况。

解决方法

预处理时增加特殊判断。

算法步骤:

  1. 读入数据并记录障碍点的横纵坐标
  2. 处理特殊情况,得到一个初始的 $ ans$ 值
    1. 上下为矩形边界的特殊情况
    2. 左右为矩形边界的特殊情况
  3. 把障碍点先按照 \(x\) 从小到大排序,\(x\) 相同时 \(y\) 从小到大
    1. 从左到右枚举每个障碍点 \(i\) 作为左边界
      1. 初始化 \(L = 0;R = Wide;maxL = Len - a[i].x\)
      2. 从左到右扫描其他障碍点 \(j\)
        1. 最优性剪枝 \(if((R-L)*maxL \le Ans) break;\)
        2. 若此点在上边界上方或下边界下方或与 \(i\) 点在同一列, 则 \(continue\)
        3. 计算比较 \(Ans = \max(Ans,(R - L) \times (a[j].x - a[i].x))\)
        4. 若 \(i\) 与 \(j\) 处在同一行则退出,因为上下边界重合后后面的点无影响
        5. 修改上下边界
      3. 从右到左枚举每个障碍点 \(i\) 作为右边界
  4. 输出 \(Ans\)

代码

#include<bits/stdc++.h>
#define N 50010
using namespace std;
struct node{
	int x,y;
}a[N];
int l,w,n,b[N],c[N],ans = 0;
bool cmp(node a,node b){
	return a.x==b.x?a.y<b.y:a.x<b.x;
}
int main(){
	scanf("%d%d%d",&l,&w,&n);
	for(int i = 1;i<=n;i++){
		scanf("%d%d",&a[i].x,&a[i].y);
		b[a[i].x] = 1,c[a[i].y] = 1;
	}
	b[0] = 1,c[0] = 1;a[++n].x = 0,a[n].y = 0;
	b[l] = 1,c[w] = 1;a[++n].x = l,a[n].y = w;
	a[++n].x = l,a[n].y = 0;
	a[++n].x = 0,a[n].y = w;
	sort(a+1,a+n+1,cmp);
	int maxl,last = 0,lt,rt,j;
	for(int i = 1;i<=l;i++){
		if(!b[i]) continue;
		ans = max(ans,w*(i-last));
		last = i;
	}
	last = 0;
	for(int i = 1;i<=w;i++){
		if(!c[i]) continue;
		ans = max(ans,l*(i-last));
		last = i;
	}
	for(int i = 1;i<=n;i++){
		lt = 0,rt = w,maxl = l-a[i].x;
		if(maxl*(rt-lt)<ans) break;
		for(j = i+1;j<=n;j++){
			if(a[j].y<lt||a[j].y>rt||a[i].x==a[j].x)continue;
			ans = max(ans,(rt-lt)*(a[j].x-a[i].x));
			if(a[j].y==a[i].y) break;
			if(a[j].y<a[i].y) lt = max(lt,a[j].y);
			else  rt = min(rt,a[j].y);
		}
		if(j>n) ans = max(ans,(rt-lt)*(l-a[i].x));
	}
	for(int i = n;i>=1;i--){
		lt = 0,rt = w,maxl = a[i].x;
		printf("%d\n",maxl*(rt-lt));
		if(maxl*(rt-lt)<ans) break;
		for(j = i-1;j>=1;j--){
			if(a[j].y<lt||a[j].y>rt||a[i].x==a[j].x)continue;
			ans = max(ans,(rt-lt)*(a[i].x-a[j].x));
			if(a[j].y==a[i].y) break;
			if(a[j].y<a[i].y) lt = max(lt,a[j].y);
			else  rt = min(rt,a[j].y);
		}
		if(j<1) ans = max(ans,(rt-lt)*a[i].x);
	}
	printf("%d",ans);
	return 0;
}

标签:P1578,障碍,浴场,边界,枚举,ans,洛谷,矩形,号点
From: https://www.cnblogs.com/cztq/p/17486335.html

相关文章

  • 洛谷 P6821 [PA2012]Tanie linie
    洛谷传送门考虑恰好选\(k\)个子段怎么做。设恰好选\(i\)个子段的和最大值为\(h_k\)。可以得到\(h_{i+1}-h_i\leh_i-h_{i-1}\),因为\(h_i\toh_{i+1}\)的过程就是多选一个子段,贡献肯定不如上一次选即\(h_{i-1}\toh_i\)大。如果它不成立,那我们可以交换......
  • 洛谷P5322 [BJOI2019] 排兵布阵
    题目大意有s名对手,n座城堡,你有m名士兵如果一名玩家向第\(i\)座城堡派遣的士兵数严格大于对手派遣士兵数的两倍,那么这名玩家就占领了这座城堡,获得\(i\)分。求最大得分数据范围对于\(10\%\)的数据:\(s=1,n\le3,m\le10\)对于\(20\%\)的数据:\(s=1,n\le10,m\le1......
  • 【若归】 【LGR-142-Div.4】洛谷入门赛 #13赛后反思
    比赛链接:【LGR-142-Div.4】洛谷入门赛#13rk288,比前几次差(可能是因为rated?)A十年OI一场空,不开longlong见祖宗#include<bits/stdc++.h>usingnamespacestd;intmain(){ longlongintn; cin>>n; cout<<"8"<<12*(n-2)<<""<<6*(n-......
  • 洛谷 P6003 总结
    题目:洛谷P6003链接:洛谷,逐月题意有一个人欠了别人\(n\)单位牛奶,每一天他会还\(y=\max(m,\frac{n-g}{x})\)单位,\(g\)为之前还的牛奶,请求出最大的\(x\)使得这个人在\(k\)天后能换至少\(k\)单位牛奶。\(1\len,m,k\le10^{12},km<n\)。思路暴力......
  • 【LGR-141-Div.2】洛谷 6 月月赛 I (前两题)
    T1:金盏花传送门直接暴力枚举前6位的值即可,记得开longlong#include<bits/stdc++.h>usingnamespacestd;#defineintlonglonginty,z,ans=1e18;signedmain(){ scanf("%lld%lld",&y,&z); for(inti=100000;i<=999999;i++){ intx=i*1000000+y; ans=min......
  • 洛谷P1587 [NOI2016] 循环之美
    原文链接:[sol]P1587[NOI2016]循环之美-icyM3tra'sBlog此为备份。题目传送门0.前言提供一种式子较为简洁且不算难写的做法。以及介绍一种较为优秀的dp版杜教筛实现。1.式子推导我们知道纯循环小数一定可以写成分母形如\(k^a-1\)的分数。因此约分后的分母一定......
  • 洛谷 P3723 [AH2017/HNOI2017]礼物
    由题面可得:\[E_j=\sum_{i=1}^{j-1}\frac{q_i}{(i-j)^2}-\sum_{i=j+1}^{n}\frac{q_i}{(i-j)^2}\]令\(q_0=0\),并将没有意义的分式的值视为\(0\),则有:\[E_j=\sum_{i=0}^j\frac{q_i}{(i-j)^2}-\sum_{i=j}^n\frac{q_i}{(i-j)^2}\]令\(A(i)......
  • 海底高铁(洛谷3406)
         #include<iostream>usingnamespacestd;constintN=100010;intp[N];//要去的城市intA[N],B[N],C[N];longlongs,ans[N];//ans差分数组intmain(){intN,M;scanf("%d%d",&N,&M);for(inti=1;i<=M......
  • 洛谷3397地毯
        问题分析:这个比y总的二维差分模板要简单一些,因为他一开始的矩阵都为0,而且矩阵是一个n方阵,那么其实可以用y总的模板来写,下面是二维差分矩阵的原理  #include<iostream>usingnamespacestd;constintN=1010;intb[N][N];voidinsert(intx1,in......
  • 洛谷 P9344. 去年天气旧亭台
    去年天气旧亭台题目背景依旧是过往的天气,过往的楼台烟雨。时间悄悄流逝着,山河仍在,人却已不是过去的人……题目描述登上楼台,旧时满面沉灰的地板映入眼帘。共有$n$块地板,地板分为两类,第$i$块地板的类别用$c_i$表示,积灰程度用$a_i$表示。注意$c_i$为$0$或$1$。现......