考虑
f[T][x][y]
表示在T时刻是否能到达
(x,y)
,那么就可以
O(Tn2)
的时间内完成转,因为n<=30,就可以把一列的状态压成一个整数,每次转移就可以通过位运算实现,这样如果没有障碍物,转移就可以
O(Tn)
接下来就考虑障碍物的情况,如果
Ki,j>1000
那么把在T以内的
Ki,j
的倍数记录下来,当T达到这个值的时候处理。
如果
Ki,j<=1000
,可以把
Ki,j
分解质因数,设
Ki,j=pc11pc22...pcnn
那么当T能同时整除
pc11
,
pc22,
…
pcnn
令
g[i][j]
表示能整除
pji
时棋盘的情况,
那么把T也分解质因数,棋盘的情况就可以表示为
g[1][c1] and g[2][c2]...and g[n][cn]
当然次数为0的也要考虑进去,为了节省时间可以令
f[i][j]=g[i][0] and g[i+1][0] ... and g[j][0]
分解质因数可以用
O(n)
预处理,
O(logn)
分解的方法。
其实也可以用O(sqrt(n))
就可以A啦
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#define N 35
#define M 1000010
using namespace std;
int x,y,n,t,now,pp,cnt;
int A[N][N];
int f[2][N];
int p[M],v[M];
int g[210][21][N];
int h[210][210][N];
int w[N];
pair<int,int> fc[M];
struct stp{
int t,x,y;
stp(int a=0,int b=0,int c=0):t(a),x(b),y(c){}
friend bool operator <(stp a,stp b){ return a.t<b.t; }
};
vector<stp> V;
vector<pair<int,int> > Ans;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void rea(int &x){
char c=nc(); x=0;
for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}
inline void First(){
for(int i=2;i<=M-10;i++){
if(!p[i]) p[++*p]=i,v[i]=*p;
for(int j=1;j<=*p&&1ll*i*p[j]<=M-10;j++){
p[i*p[j]]=1;
v[i*p[j]]=j;
if(i%p[j]==0) break;
}
}
for(int i=1;i<=*p;i++)
if(p[i]<=1000) pp=i; else break;
}
inline void Add(int k,int x,int y){
for(int i=1;i<=pp;i++){
int c=0;
while(k%p[i]==0) c++,k/=p[i];
for(;c<=20;c++) g[i][c][x]|=1<<y;
}
}
inline void fac(int x){
cnt=0;
while(x^1){
int c=0,t=v[x];
while(x%p[t]==0) c++,x/=p[t];
fc[++cnt]=make_pair(t,c);
}
sort(fc+1,fc+1+cnt);
int lst=1;
for(int i=1;i<=cnt&&fc[i].first<=pp;i++){
for(int j=1;j<=n;j++) w[j]&=g[fc[i].first][fc[i].second][j];
if(lst<fc[i].first) for(int j=1;j<=n;j++) w[j]&=h[lst][fc[i].first-1][j];
lst=fc[i].first+1;
}
if(lst<pp) for(int i=1;i<=n;i++) w[i]&=h[lst][pp][i];
}
int main(){
rea(n); rea(t); First();
rea(x); rea(y);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
rea(A[i][j]);
if(A[i][j]>=1000)
for(int k=1;k*A[i][j]<=t;k++) V.push_back(stp(k*A[i][j],i,j));
else Add(A[i][j],i,j);
}
sort(V.begin(),V.end());
for(int i=1;i<=pp;i++)
for(int j=i;j<=pp;j++)
for(int s=1;s<=n;s++){
h[i][j][s]=(1<<n+1)-1;
for(int k=i;k<=j;k++)
h[i][j][s]&=g[k][0][s];
}
f[0][x]|=1<<y;
/*printf("#%d:\n",0);
for(int i=1;i<=n;i++,putchar('\n'))
for(int j=1;j<=n;j++) printf("%d ",f[0][i]>>j&1);*/
for(int i=1,P=0;i<=t;i++){
now^=1;
for(int j=1;j<=n;j++) f[now][j]=0,w[j]=(1<<n+1)-1;
for(int j=1;j<=n;j++){
if(j>1) f[now][j]|=(f[now^1][j-1]>>2)|(f[now^1][j-1]<<2);
if(j<n) f[now][j]|=(f[now^1][j+1]>>2)|(f[now^1][j+1]<<2);
if(j>2) f[now][j]|=(f[now^1][j-2]>>1)|(f[now^1][j-2]<<1);
if(j<n-1) f[now][j]|=(f[now^1][j+2]>>1)|(f[now^1][j+2]<<1);
}
fac(i);
while(P<V.size()&&V[P].t==i) w[V[P].x]|=(1<<V[P].y),P++;
for(int j=1;j<=n;j++) f[now][j]&=w[j];
/* printf("#w%d:\n",i);
for(int j=1;j<=n;j++,putchar('\n'))
for(int k=1;k<=n;k++)
printf("%d ",w[j]>>k&1);
printf("#%d:\n",i);
for(int j=1;j<=n;j++,putchar('\n'))
for(int k=1;k<=n;k++)
printf("%d ",f[now][j]>>k&1);*/
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(f[now][i]&(1<<j)) Ans.push_back(make_pair(i,j));
printf("%d\n",Ans.size());
for(int i=0;i<Ans.size();i++) printf("%d %d\n",Ans[i].first,Ans[i].second);
return 0;
}