Title

AT_abc182_e [ABC182E] Akari 题解

题目传送门

题目大意

已知在一个 H×W 的网格中,有n个灯泡和m个障碍物,每个灯泡都可以照亮它所在的行和列的格子,知道光线被障碍物阻挡,即光线从灯泡发出,知道遇到障碍物或边界结束。求共有多少个格子被照亮。

正解思路

  1. 记录下每个灯泡的坐标 xiyi ,定义一个二维数组 Map[H][W] ,如果该格子上有障碍物,就把 Map 中这一格的值赋为2,如果是灯泡,赋值为一。定义一个布尔类型的二维数组 vis[H][W] ,记录每个格子有没有光照。定义一个 int 类型的变量 cnt ,记录有多少个格子有光照,定义一个变量 now ,记录当前的状态。

  2. 对于每个格子,我们可以根据上下左右四个方向的格子的状态更新。因此,按照从上到下、从下到上、从左到右、从右到左的四个顺序遍历整个网格,每次遍历前把 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

  3. 最终,我们只需要遍历一遍整个网格,如果格子的 vis 值为1,那么 cnt++ 。遍历完后输出 cnt 就可以了。

时间复杂度: O(4×nm) ;空间复杂度: O(n×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;
}

蒟蒻的第一篇题解,求过。

posted @   UncleSam_Died  阅读(3)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示