洛谷傳送門
BZOJ傳送門
解析:
首先我們給每個格子一個決策方向,向下或向右。可以很輕易的發現,如果想要合法,所有循環對角線的格子必須要決策相同,不然的話會有格子無法被達到。
於是我們發現在所有對角線的決策相同的時候,機器人的路徑是一個循環,且循環節長度爲,而且合法的循環節長度只能爲,由裴蜀定理,單次循環中向下和向右的長度也必須和循環節長度和當前維度長度互質。
同時通過感性理解 我們可以發現所有這樣的解都是合法的。
那麼我們考慮枚舉單個循環中向下和向右的方案數,然後對合法的計算答案。
顯然我們在走過個循環的時候,爲了轉移到第個循環,只需要維護當前下的前層疊加矩陣和前層的疊加矩陣。計算出在前個矩陣中不經過到達當前位置的方案數,和從當前位置開始不經過,到達當前循環終止位置的方案數,就能愉快的完成轉移了。
代碼:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define cs const
cs int N=102;
bool ma[N][N];
bool bas[2][N][N];
cs int mod=998244353;
inline int add(cs int &a,cs int &b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(cs int &a,cs int &b){return a<b?a-b+mod:a-b;}
inline int mul(cs int &a,cs int &b){return (ll)a*b%mod;}
int n,m,ans,dx,dy;
int pre[N][N],suf[N][N];
inline void solve(bool b1[N][N],bool b2[N][N],cs int &tx,cs int &ty,int tim){
for(int re i=1;i<=dx+1;++i)
for(int re j=1;j<=dy+1;++j)b1[i][j]=b2[i][j]||ma[tx+i][ty+j];
for(int re i=1;i<=dx+1;++i)
memset(pre[i]+1,0,sizeof(int)*(dy+1)),
memset(suf[i]+1,0,sizeof(int)*(dy+1));
if(b1[1][1]==0){
pre[1][1]=1;
for(int re i=1;i<=dx+1;++i)
for(int re j=1;j<=dy+1;++j)
pre[i][j+1]=add(pre[i][j+1],(b1[i][j+1]==0)*pre[i][j]),
pre[i+1][j]=add(pre[i+1][j],(b1[i+1][j]==0)*pre[i][j]);
}
if(b2[dx+1][dy+1]==0){
suf[dx+1][dy+1]=1;
for(int re i=dx+1;i;--i)
for(int re j=dy+1;j;--j)
suf[i][j-1]=add(suf[i][j-1],(b2[i][j-1]==0)*suf[i][j]),
suf[i-1][j]=add(suf[i-1][j],(b2[i-1][j]==0)*suf[i][j]);
}
for(int re i=1;i<=dx+1;++i)
for(int re j=1;j<=dy+1;++j){
if(b1[i][j]==0)continue;
int f;
if(i==1&&j==1)f=1;
else f=add(pre[i-1][j],pre[i][j-1]);
ans=add(ans,mul(mul(tim+i+j-2,f),suf[i][j]));
}
}
char s[N];
inline void solve(){
cin>>n>>m;ans=0;
for(int re i=1;i<=n;++i){
cin>>(s+1);
for(int re j=1;j<=m;++j)ma[i][j]=ma[i+n][j]=ma[i+n][j+m]=ma[i][j+m]=s[j]=='1';
}
int d=__gcd(n,m);
for(dx=0,dy=d;dx<=d;++dx,--dy){
if((dx==0&&n!=1)||(dy==0&&m!=1))continue;
if(__gcd(dx,d)!=1||__gcd(dx,n)!=1||__gcd(dy,m)!=1)continue;
for(int re i=0;i<=dx+1;++i)
memset(bas[0][i]+1,0,sizeof(bool)*(dy+1)),
memset(bas[1][i]+1,0,sizeof(bool)*(dy+1));
for(int re tim=0,p=1;tim<n*m;tim+=d,p^=1)
solve(bas[p],bas[p^1],(tim*dx/d)%n,(tim*dy/d)%m,tim);
}
cout<<ans<<"\n";
}
int T;
signed main(){
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
cin>>T;
while(T--)solve();
return 0;
}