时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
有一个沿海地区,可以看作有n行m列的城市,第i行第j列的城市海拔为h[i][j]。
由于沿海,所以这个地区经常会发生海啸。
海啸发生时,部分城市会被淹没,具体来说,海水高度会达到d,因此海拔低于d的城市都会被淹没。
现在有q次询问,每次问你一个矩形区域中,有多少城市不会被淹没。
第一行三个整数n,m,d,具体含义见题目描述。
接下来n行,每行m个整数,其中第i行第j列的整数为h[i][j],具体含义见题目描述。
第n+2行一个整数q,表示询问数。
接下来q行,每行四个整数a,b,x,y,
表示询问从第a行第b列到第x行第y列的矩形地区中,有多少地区不会被淹没。
即有多少个i,j,满足 a≤i≤x,b≤j≤ya≤i≤x,b≤j≤y ,且 h[i][j]≥dh[i][j]≥d 。
共q行,第i行一个整数,表示第i个询问的答案。
示例1
3 3 3
1 2 3
2 1 5
4 3 2
2
1 2 2 3
2 1 3 3
2
3
1≤n×m≤10^6
1≤q≤10^5
0≤d,h[i][j]≤10^9
1≤a≤x≤n,1≤b≤y≤m
笔者刚看到题,海平面,城市,淹没等等字眼第一反应搜索,读完题面,发现不需要搜索因为题目中城市(点集)之间没有连通关系,城市之间是不相关的。
接下来下意识的觉得,哇,连搜索都不用,那不是好简单,看来这题是模拟题意。
顺着思路于是开始着手写代码,这个时候问题出现了行列范围是1≤n×m≤10^6,这个数组怎么开?如果直接开二维数组h[1000001][1000001]是不合理的,这个数组一共有10^6*10^6=10^12数量级的元素,空间爆掉了。那么这里说三种方法
1、官方给出的方法是定义一个**h二维指针数组,读取m,n后new重定义数组大小。
2、使用C++STL库封装的vector动态数组。
3、因为行*列<=10^6,可以用一个一维数组h[1000001],通过下标对n列的整除性实现降维。即每个h[i]相当于二维数组的s[i/n][i%n]。
数组考虑完了,下面开始模拟题意。
这时又有新的问题了,直接遍历是不可行的,如果每次询问都进行遍历那么操作次数是q*(x-a)*(y-b)在本题的数据规模下,时间复杂度太高了,会超出时间限制。那么需要进行预处理,使用前缀和的思想。用数组pre[x][y]的值表示,存放从1,1到x,y这个矩形内的不会被淹没的城市数,则矩形x1y1x2y2内的不会被淹没的城市数量可表示为 pre[x2][y2] - pre[x2][y1-1] - pre[x1-1][y2] + pre[x1-1][y1-1]。
(求pre[x][y]的值if(x >= d)pre[i][j] = 1 + pre[i-1][j] + pre[i][j-1] - pre[i-1][j-1];
else pre[i][j] = pre[i-1][j] + pre[i][j-1] - pre[i-1][j-1];
就是反向使用上面的前缀和思路,即累加的思想
)
下面几种代码供大家参考
数组降维
//数组降维
#include
using namespace std;
int h[1000005],s[1000005];
int main(){
int m,n,d,q,a,b,x,y,t,t1,t2,t3;
scanf("%d%d%d",&m,&n,&d);
for(int i=0;i=d)t++;
s[i]=t;
}
t=0;
for(int i=0;i=d)t++;
s[i*n]=t;
}
for(int i=1;i=d)t=1;
s[i*n+j]=t+s[(i-1)*n+j]+s[i*n+j-1]-s[(i-1)*n+j-1];
}
}
scanf("%d",&q);
for(int i=1;i<=q;i++){
scanf("%d%d%d%d",&a,&b,&x,&y);
t=0;
t=s[(x-1)*n+(y-1)];
t3=s[(a-2)*n+(b-2)];
if(a<2)t1=t3=0;else t1=s[(a-2)*n+(y-1)];
if(b<2)t2=t3=0;else t2=s[(x-1)*n+(b-2)];
t=t-t2-t1+t3;
printf("%d\n",t);
}
return 0;
}
动态数组
//动态数组
#include
#include
#include
using namespace std;
vector > e;
int n,m;
int main()
{
int d;
scanf("%d%d%d",&n,&m,&d);
e=vector >(n+1,vector(m+1));
for(int i=1,recv;i<=n;++i)
for(int j=1;j<=m;++j)
{
scanf("%d",&recv);
e[i][j]=(recv>=d?1:0)+e[i-1][j]+e[i][j-1]-e[i-1][j-1];
}
int q;
scanf("%d",&q);
for(int a,b,c,d;q--;)
{
scanf("%d%d%d%d",&a,&b,&c,&d);
printf("%d\n",e[c][d]-e[a-1][d]-e[c][b-1]+e[a-1][b-1]);
}
return 0;
}