目录
4、子矩阵(第十四届蓝桥杯省赛C++ C组、第十四届蓝桥杯省赛Java C组/研究生组、第十四届蓝桥杯省赛Python A组)
1、矩形牛棚(usaco training 6.1)
作为一个资本家,农夫约翰希望通过购买更多的奶牛来扩大他的牛奶业务。
因此,他需要找地方建立一个新的牛棚。
约翰购买了一大块土地,这个土地可以看作是一个 R行(编号 1∼R)C列(编号 1∼C)的方格矩阵。
不幸的是,他发现其中的部分方格区域已经被破坏了,因此他无法在整个 R×C 的土地上建立牛棚。
经调查,他发现共有 P 个方格内的土地遭到了破坏。
建立的牛棚必须是矩形的,并且内部不能包含被破坏的土地。
请你帮约翰计算,他能建造的最大的牛棚的面积是多少。
输入格式
第一行包含三个整数 R,C,P。
接下来 P 行,每行包含两个整数 r,c,表示第 r 行第 c 列的方格区域内土地是被破坏的。
输出格式
输出牛棚的最大可能面积。
数据范围
1≤R,C≤3000
0≤P≤30000
1≤r≤R1
1≤c≤C1
输入样例:
3 4 2
1 3
2 1
输出样例:
6
思路:
对于每行(预处理好每个方块上面最多能用的方块的个数),枚举其中的每列,分别判断出左右两边第一列比该列上面最多可用方块少的位置,然后底乘高算出面积,维护最大值即可
预处理的过程:
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(g[i][j]==0)
{
h[i][j]=h[i-1][j]+1;
}
}//记录这一位置上面能用的格子是多少
判断左右边界的过程:
int work(int a[])
{
a[0]=-1,a[m+1]=-1;
int tt=0;
//枚举左边第一个比这个位置上面能用的格子少的左边界
stk[++tt]=0;//把左边界加进去
for(int i=1;i<=m;i++)
{
while(a[i]<=a[stk[tt]])tt--;//栈顶元素大于等于当前元素的话弹出栈顶
l[i]=stk[tt];
stk[++tt]=i;
}
tt=0;
stk[++tt]=m+1;
for(int i=m;i>=1;i--)
{
while(a[stk[tt]]>=a[i])tt--;
r[i]=stk[tt];
stk[++tt]=i;
}
int res=0;
for(int i=1;i<=m;i++)
{
res=max(res,a[i]*(r[i]-l[i]-1));
}
return res;
}
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=3010;
int n,m,p;
int g[N][N],h[N][N];
int l[N],r[N];
int stk[N];
int work(int a[])
{
a[0]=-1,a[m+1]=-1;
int tt=0;
//枚举左边第一个比这个位置上面能用的格子少的左边界
stk[++tt]=0;//把左边界加进去
for(int i=1;i<=m;i++)
{
while(a[i]<=a[stk[tt]])tt--;//栈顶元素大于等于当前元素的话弹出栈顶
l[i]=stk[tt];
stk[++tt]=i;
}
tt=0;
stk[++tt]=m+1;
for(int i=m;i>=1;i--)
{
while(a[stk[tt]]>=a[i])tt--;
r[i]=stk[tt];
stk[++tt]=i;
}
int res=0;
for(int i=1;i<=m;i++)
{
res=max(res,a[i]*(r[i]-l[i]-1));
}
return res;
}
int main()
{
cin>>n>>m>>p;
for(int i=0;i<p;i++)
{
int r,c;
cin>>r>>c;
g[r][c]=1;//标记为破坏
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(g[i][j]==0)
{
h[i][j]=h[i-1][j]+1;
}
}//记录这一位置上面能用的格子是多少
int res=0;
for(int i=1;i<=n;i++)
{
res=max(res,work(h[i]));
}
cout<<res;
return 0;
}
2、单调栈(单调栈模板)
给定一个长度为 N 的整数数列,输出每个数左边第一个比它小的数,如果不存在则输出 −1。
输入格式
第一行包含整数 N,表示数列长度。
第二行包含 N 个整数,表示整数数列。
输出格式
共一行,包含 N 个整数,其中第 i 个数表示第 i 个数的左边第一个比它小的数,如果不存在则输出 −1。
数据范围
1≤N≤1e5
1≤数列中元素≤1e9
输入样例:
5
3 4 2 7 5
输出样例:
-1 3 -1 2 2
思路:
经典单调栈模板
基本步骤:
1、维护单调性
while(tt>0 && s[tt]>=x)tt--;
2、处理要求的操作
if(tt<=0)cout<<"-1"<<" ";
else cout<<s[tt]<<" ";
3、入栈
s[++tt]=x;
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1