题解 2019 集训队互测 Day 5 国际象棋

题解 2019 集训队互测 Day 5 国际象棋

题面

loj

解析

首先考虑一个 \(O(mn)^3\) 的高斯消元做法.

为了方便讲,棋盘里的每个格子都有一个编号.

考虑某个点 \(i\),设它下一步能走到的点为 \(p_j,j\in [0,7]\).

(这里的编号是用的 \(0\sim 7\))

设它走出棋盘的概率为 \(f_i\),则有:

\(f_i=\sum\limits_{j=0}^{7}w_jf_{p_j}+1\)

表示下一步可能走到的某个点的步数再加上这一步,

那么移项后有:\(f_i-\sum\limits_{j=0}^{7}w_jf_{p_j}=1\).

\(f_i\) 作为变量,则有 \(n\times 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-\sum\limits_{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\n",ans);
	}
	return 0;
}
posted @ 2020-06-04 22:07  permzf  阅读(363)  评论(0编辑  收藏  举报