题解 P7243 【最大公约数】
这题一眼看上去十分复杂,但是仔细想一想还是蛮简单的。
首先,我们模拟经过一天以后所有人的个性值,如果此时没有个性值为
然后我们思考第二天那些人的个性值会变为
code:
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#define ri register int
#define int long long
inline int read() {
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=2e3+5;
int n,m,xx,yy;
int last[N][N],now[N][N],vis[N][N];
int qx[5]={1,-1,0,0};
int qy[5]={0,0,-1,1};
struct node{
int x,y,d;
};
std::queue<node>q;
int gcd(int x,int y){
if(y==0)return x;
else return gcd(y,x%y);
}
signed main(void){
n=read(),m=read();
for(ri i=1;i<=n;i++){
for(ri j=1;j<=m;j++){
last[i][j]=read();
}
}
xx=read(),yy=read();
if(last[xx][yy]==1)printf("0"),exit(0);//特判
for(ri i=1;i<=n;i++){
for(ri j=1;j<=m;j++){
int ans=last[i][j];
if(i!=1)ans=gcd(ans,last[i-1][j]);
if(i!=n)ans=gcd(ans,last[i+1][j]);
if(j!=1)ans=gcd(ans,last[i][j-1]);
if(j!=m)ans=gcd(ans,last[i][j+1]);
now[i][j]=ans;
}
}//计算第一天所有人的个性值
for(ri i=1;i<=n;i++){
for(ri j=1;j<=m;j++){
if(now[i][j]==1)q.push((node){i,j,1});
}
} //将个性值为1的人丢进队列
if(q.size()==0)printf("-1");//判断无解
while(q.size()){
node p=q.front();q.pop();
if(vis[p.x][p.y])continue;
vis[p.x][p.y]=true;
if(p.x==xx&&p.y==yy){
printf("%d",p.d);exit(0);//找到答案
}
for(ri i=0;i<4;i++){
int px=p.x+qx[i],py=p.y+qy[i];
if(!((px>=1&&px<=n&&py>=1&&py<=m)&&(!vis[px][py])))continue;
q.push((node){px,py,p.d+1});//将他周围的4个人丢进队列,并标记他们最短第几天个性值为1
}
}
return 0;
}
最慢的点跑了1.93s(逃