AT_abc182_e [ABC182E] Akari 题解
题目大意
已知在一个 $H\times W$ 的网格中,有$n$个灯泡和$m$个障碍物,每个灯泡都可以照亮它所在的行和列的格子,知道光线被障碍物阻挡,即光线从灯泡发出,知道遇到障碍物或边界结束。求共有多少个格子被照亮。
正解思路
-
记录下每个灯泡的坐标 $x_i$ 和 $y_i$ ,定义一个二维数组 $Map[H][W]$ ,如果该格子上有障碍物,就把 $Map$ 中这一格的值赋为2,如果是灯泡,赋值为一。定义一个布尔类型的二维数组 $vis[H][W]$ ,记录每个格子有没有光照。定义一个 $int$ 类型的变量 $cnt$ ,记录有多少个格子有光照,定义一个变量 $now$ ,记录当前的状态。
-
对于每个格子,我们可以根据上下左右四个方向的格子的状态更新。因此,按照从上到下、从下到上、从左到右、从右到左的四个顺序遍历整个网格,每次遍历前把 $now$ 的值初始化为1。如果该格是灯泡,那么把 $now$ 的值赋为1,如果是障碍物,那么赋值为0。这时,一个格子的光照状态就可以根据 $now$ 来更新了:如果这个格子在这一次更新之前就已经有光照了,那么不更新;如果 $now$ 的值为1,说明之前的格子及当前格子中没有障碍物,也就是说,这个格子是一定会有光照的,那么我们把这个格子的 $vis$ 更新为1;如果 $now$ 的值为0,说明当前格子或当前格子之前的个子中已经有障碍物了,说明光线无法到达,赋值为0。简而言之,如果当前格子的 $vis$ 为1,那么最后他的 $vis$ 值也为1;如果当前格子的 $vis$ 为0,那么它 $vis$ 的值就等于 $now$ 的值。到这里,我们惊奇的发现,这不就是逻辑或吗!所以我们可以得到关系式 $vis[i][j]=vis[i][j]|now$ 。
-
最终,我们只需要遍历一遍整个网格,如果格子的 $vis$ 值为1,那么 $cnt++$ 。遍历完后输出 $cnt$ 就可以了。
时间复杂度: $O(4\times nm)$ ;空间复杂度: $O(n\times m)$ ;预计得分:100。
AC代码
#include<iostream>
#pragma GCC opzitime(2)
using namespace std;
inline void read(int &x){
x=0;int f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-f;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
x*=f;return;
}
inline void put(int x){
if(x<0) putchar('-'),x=-x;
if(x>9) put(x/10);
putchar(x%10+'0');return;
}inline void write(int x){put(x);putchar('\n');}
int Nu1,Nu2,n,m,x,y,cnt,now;
int map[1505][1505];
bool vis[1505][1505];
inline void work(){
for(int i=1;i<=n;i++){
now=0;
for(int j=1;j<=m;j++){//从上到下,从左到右更新
if(map[i][j]==2) now=0; //如果这个格子本身就是障碍物,now=0
else if(map[i][j]==1)//如果这个格子本身就是光源,那么now-1
now=1,vis[i][j]|=now;//同时更新vis
else vis[i][j]|=now;//如果这是空格子,根据now更新
}
now=0;
for(int j=m;j>=1;j--){//从上到下,从右到左更新
if(map[i][j]==2) now=0; //如果这个格子本身就是障碍物,now=0
else if(map[i][j]==1)//如果这个格子本身就是光源,那么now-1
now=1,vis[i][j]|=now;//同时更新vis
else vis[i][j]|=now;//如果这是空格子,根据now更新
}
}
for(int j=1;j<=m;j++){
now=0;
for(int i=1;i<=n;i++){//从左到右,从上到下更新
if(map[i][j]==2) now=0; //如果这个格子本身就是障碍物,now=0
else if(map[i][j]==1)//如果这个格子本身就是光源,那么now-1
now=1,vis[i][j]|=now;//同时更新vis
else vis[i][j]|=now;//如果这是空格子,根据now更新
}
now=0;
for(int i=n;i>=1;i--){//从左到右,从下到上更新
if(map[i][j]==2) now=0; //如果这个格子本身就是障碍物,now=0
else if(map[i][j]==1)//如果这个格子本身就是光源,那么now-1
now=1,vis[i][j]|=now;//同时更新vis
else vis[i][j]|=now;//如果这是空格子,根据now更新
}
}
}
signed main(){
read(n),read(m),read(Nu1),read(Nu2);
for(register int i=1;i<=Nu1;i++)//读入灯泡坐标
read(x),read(y),map[x][y]=1;
for(register int i=1;i<=Nu2;i++)//读入障碍物坐标
read(x),read(y),map[x][y]=2;
work();int cnt=0;
for(int i=1;i<=n;i++){//计算共有多少个格子有光照
for(int j=1;j<=m;j++){
if(vis[i][j]) cnt++;
}
}
write(cnt);//输出
return 0;
}
蒟蒻的第一篇题解,求过。

浙公网安备 33010602011771号