luogu P7243\color{green}{\texttt{luogu P7243}}luogu P7243
[Problem]\color{blue}{\texttt{[Problem]}}[Problem]
[Solution]\color{blue}{\texttt{[Solution]}}[Solution]
稍微思考一下,就可以得到如下的性质:
- 如果一个位置 (x,y)(x,y)(x,y) 上的数变成了 111,那么第二天它四周围尚未变成 111 的数都会变成 111。(可以形象地理解为 111 会传染)
- 如果一个位置 (x,y)(x,y)(x,y) 在初始状态下与它四周的数的 gcd\gcdgcd 值为 111,那么它在第一天就会变成 111。从第二天开始,它就会开始传染四周。
- 如果初始转台下不存在如 222 所说的点,那么,答案就是 −1-1−1。
所以,我们可以用 bfs
来解决这道题。开一个数组保存每个点会在第几天变成 111 即可。
注意,如果初始就是 111,那么这个点的答案应该是 000。
[code]\color{blue}{\texttt{[code]}}[code]
int times[2010][2010];
bool visit[2010][2010];
ll a[2010][2010];int n,m;
inline ll gcd(ll u,ll v){
if (v==0) return u;
else return gcd(v,u%v);
}
struct node{int x,y;};
inline bool check(int x,int y){
return (x>0&&x<=n)&&(y>0&&y<=m);
}
inline bool First(int x,int y){
register ll g=a[x][y];//最大公因数
if (check(x-1,y)) g=gcd(g,a[x-1][y]);
if (check(x,y-1)) g=gcd(g,a[x][y-1]);
if (check(x+1,y)) g=gcd(g,a[x+1][y]);
if (check(x,y+1)) g=gcd(g,a[x][y+1]);
return g==1;
}
const int dx[]={1,0,-1,0};
const int dy[]={0,1,0,-1};
inline void bfs(){
queue<node> q;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if (First(i,j)){
q.push((node){i,j});
times[i][j]=(a[i][j]!=1);
visit[i][j]=false;
}
while (!q.empty()){
node z=q.front();q.pop();
for(int i=0;i<4;i++){
int x=z.x+dx[i],y=z.y+dy[i];
if (!check(x,y)) continue;
if (!visit[x][y]) continue;
times[x][y]=times[z.x][z.y]+1;
q.push((node){x,y});
visit[x][y]=false;
}
}
}
int main(){
n=read();m=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
a[i][j]=read();
memset(times,-1,sizeof(times));
memset(visit,true,sizeof(visit));
bfs();//利用 bfs 求解答案
int l=read(),r=read();
printf("%d",times[l][r]);
return 0;
}