版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/88362566
洛谷传送门
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;
}