题解 2019 集训队互测 Day 5 国际象棋
题面
解析
首先考虑一个 (O(mn)^3) 的高斯消元做法.
为了方便讲,棋盘里的每个格子都有一个编号.
考虑某个点 (i),设它下一步能走到的点为 (p_j,jin [0,7]).
(这里的编号是用的 (0sim 7))
设它走出棋盘的概率为 (f_i),则有:
(f_i=sumlimits_{j=0}^{7}w_jf_{p_j}+1)
表示下一步可能走到的某个点的步数再加上这一步,
那么移项后有:(f_i-sumlimits_{j=0}^{7}w_jf_{p_j}=1).
把 (f_i) 作为变量,则有 (n imes m) 个方程,高斯消元即可.
但是问题是变量太多了.
考虑把前两行和第一列的 (f_i) 作为变量,
通过画图可以发现位置在 ((3,2)) 的格子的 (f) 可以通过前面设定的变量表示出来.
继续类推,所有格子的 (f) 都可以通过设定的那些变量表现出来.
并且可以发现,((3,2)) 是由 ((1,1)) 通过(frac{w_4}{P}) 的概率走到的((w) 是从 (0) 开始的)
那么我们可以通过 (f_i) 及其它的 (7) 项推出 (f_{p_4}).
即:(f_{p_4}=frac{f_i-sumlimits_{j=0&j!=4}^{7}w_jf_{p_j}-1}{w_4})
而要是 (p_4) 在棋盘外面,则期望步数 (f_{p_4}=0),
就可以得到一个关于设定的变量的方程了.
然后高斯消元即可,复杂度 (O(n+m)^3).
询问时把变量带进式子里即可.
code
#include <iostream>
#include <cstring>
#include <cstdio>
#define ll long long
using namespace std;
inline int read(){
int sum=0,f=1;char c=getchar();
while(c>'9'||c<'0'){if(c=='-') f=-1;c=getchar();}
while(c<='9'&&c>='0'){sum=sum*10+c-'0';c=getchar();}
return f*sum;
}
const int N=205;
const int Mod=998244353;
int n,m;
ll a[N*3][N*3],f[N][N][N*3],w[N];
int dx[8]={-2,-1,1,2,2,1,-1,-2};
int dy[8]={-1,-2,-2,-1,1,2,2,1};
inline ll fpow(ll a,ll b){
ll ret=1;
while(b){if(b&1) ret=ret*a%Mod;a=a*a%Mod;b>>=1;}
return ret;
}
inline void guass(int cnt){
for(int i=1;i<=cnt;i++){
int p=-1;
for(int j=i;j<=cnt;j++)
if(a[j][i]){p=j;break;}
for(int j=1;j<=cnt+1;j++)
swap(a[i][j],a[p][j]);
ll inv=fpow(a[i][i],Mod-2);
for(int j=1;j<=cnt+1;j++) a[i][j]=a[i][j]*inv%Mod;
for(int j=1;j<=cnt;j++){
if(i==j||!a[j][i]) continue;
ll x=a[j][i];
for(int k=1;k<=cnt+1;k++) a[j][k]=(a[j][k]-a[i][k]*x%Mod+Mod)%Mod;
}
}
}
inline void Add(ll &x,ll y){
x=(x+y)%Mod;x+=Mod;
if(x>Mod) x-=Mod;
}
inline void Mul(ll &x,ll y){x=x*y%Mod;}
signed main(){
n=read();m=read();
for(int i=0;i<8;i++) w[i]=read();
ll P=0;
for(int i=0;i<8;i++) P=(P+w[i])%Mod;
P=fpow(P,Mod-2);
for(int i=0;i<8;i++) w[i]=1ll*w[i]*P%Mod;
int tot=0,tt=0;
for(int i=1;i<=2;i++)
for(int j=1;j<=m;j++) f[i][j][++tot]=1;
for(int i=3;i<=n;i++) f[i][1][++tot]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
int x=i+2,y=j+1;
for(int k=1;k<=tot+1;k++) f[x][y][k]=f[i][j][k];
f[x][y][tot+1]++;
for(int k=0;k<8;k++){
if(k==4) continue;
int i1=i+dx[k],j1=j+dy[k];
if(i1<1||j1<1||i1>n||j1>m) continue;
for(int l=1;l<=tot+1;l++) Add(f[x][y][l],-f[i1][j1][l]*w[k]%Mod);
}
ll inv=fpow(w[4],Mod-2);
for(int k=1;k<=tot+1;k++) Mul(f[x][y][k],inv);
if(x>n||y>m){
tt++;
for(int k=1;k<=tot+1;k++) a[tt][k]=f[x][y][k];
}
}
guass(tot);
int Q=read();
while(Q--){
int x=read(),y=read();
ll ans=-f[x][y][tot+1];
for(int i=1;i<=tt;i++) Add(ans,f[x][y][i]*a[i][tot+1]);
printf("%lld
",ans);
}
return 0;
}