题目传送门
高斯消元思维题
对于从点 ( i , j ) (i,j) (i,j)走出棋盘,我们发现结束的状态十分的多,不妨换个思路:
从棋盘外走到点 ( i , j ) (i,j) (i,j).
那么我们可以设计 D P DP DP:
f i , j : 走到点( i , j )的期望经过回合 f_{i,j}:走到点(i,j)的期望经过回合 fi,j:走到点(i,j)的期望经过回合
那么所有在棋盘外的 f i , j = 0 f_{i,j}=0 fi,j=0
设 { d x i , d y i } \{dx_i,dy_i\} {dxi,dyi}为一个方向的偏移,一共有 8 8 8种,令它们的下标从 0 0 0开始
那么就写出转移:
f i , j = ∑ k = 0 k < 8 p k ∗ f i + d x k , j + d y k f_{i,j}=\sum_{k=0}^{k<8}p_k*f_{i+dx_k,j+dy_k} fi,j=k=0∑k<8pk∗fi+dxk,j+dyk
然后发现转移有环,不可直接转移,要用高斯消元求解
稍微计算一下复杂度:
一共有 n m nm nm个未知量,即 n m nm nm个方程,所以是 O ( ( n m ) 3 ) O((nm)^3) O((nm)3)
写好一点的话可以拿 60 p t s 60pts 60pts,对于 T 4 T4 T4来说已经不错了
考虑优化高斯消元
一个经典的想法就是设主元,减少方程数
而发现确实如此,我们知道:
f i , j = ∑ k = 0 k < 8 p k ∗ f i + d x k , j + d y k f_{i,j}=\sum_{k=0}^{k<8}p_k*f_{i+dx_k,j+dy_k} fi,j=k=0∑k<8pk∗fi+dxk,j+dyk
那么就有:
f i + d x 0 , j + d y 0 = f i , j ∑ k = 0 ( k < 8 ) ∧ ( k ≠ 0 ) p k ∗ f i + d x k , j + d y k p 0 f i + d x 1 , j + d y 1 = f i , j ∑ k = 0 ( k < 8 ) ∧ ( k ≠ 1 ) p k ∗ f i + d x k , j + d y k p 1 . . . . . . \begin{aligned} &f_{i+dx_0,j+dy_0}=\frac{f_{i,j}\sum_{k=0}^{(k<8)\wedge(k\ne0)}p_k*f_{i+dx_k,j+dy_k} }{p_0} \\ &f_{i+dx_1,j+dy_1}=\frac{f_{i,j}\sum_{k=0}^{(k<8)\wedge(k\ne1)}p_k*f_{i+dx_k,j+dy_k} }{p_1} \\ &...... \end{aligned} fi+dx0,j+dy0=p0fi,j∑k=0(k<8)∧(k=0)pk∗fi+dxk,j+dykfi+dx1,j+dy1=p1fi,j∑k=0(k<8)∧(k=1)pk∗fi+dxk,j+dyk......
我们就根据其构造新的方程组即可
最后回代系数算出真实结果即可
#include
using namespace std;
typedef long long ll;
const int dx[]={2,1,-1,-2,-2,-1,1,2};
const int dy[]={1,2,2,1,-1,-2,-2,-1};
const int N=600,mod=998244353,M=2e2+7;
int a[N][N],c[N],ans[M*M],down[N];
int ljh[M][M][N];
int cnt,cnt1,n,m,sum;
int w[17],invw[17];
int qpow(int a,int b){
int res=1; while(b){
if(b&1) res=1ll*res*a%mod;
a=1ll*a*a%mod,b>>=1;
}
return res;
}
int gett(int x,int y) { return (x-1)*m+y;}
int inv(int x){ return qpow(x,mod-2); }
bool check(int x,int y){ return (x>=1&&x<=n&&y>=1&&y<=m);}
void Gauss(int n){
for(int i=1;i<=n;i++) {
int k=0;
for(int j=i;j<=n;j++) {
if(a[j][i]) {k=j;break;}
}
if(!k) return ;
for(int j=1;j<=n+1;j++) swap(a[i][j],a[k][j]);
int p=inv(a[i][i]);
for(int j=i;j<=n+1;j++) a[i][j]=1ll*a[i][j]*p%mod;
for(int j=1;j<=n;j++) {
if(j==i) continue;
int tmp=a[j][i];
for(int k=1;k<=n+1;k++) {
a[j][k]-=1ll*a[i][k]*tmp%mod;;
a[j][k]=(a[j][k]%mod+mod)%mod;
}
}
}
}
void work() {
for(int i=1;i<=m;i++) {
ljh[1][i][++cnt]=1,down[cnt]=gett(1,i);
ljh[2][i][++cnt]=1,down[cnt]=gett(2,i);
}
for(int i=3;i<=n;i++) ljh[i][1][++cnt]=1,down[cnt]=gett(i,1);
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
if(check(i+2,j+1)) {
for(int t=1;t<=cnt+1;t++) ljh[i+2][j+1][t]=ljh[i][j][t];
for(int k=0;k<8;k++) {
int nx=i-dx[k],ny=j-dy[k];
if((k==4)||(!check(nx,ny))) continue;
for(int t=1;t<=cnt+1;t++){
ljh[i+2][j+1][t]-=1ll*ljh[nx][ny][t]*w[k]%mod;
ljh[i+2][j+1][t]=(ljh[i+2][j+1][t]%mod+mod);
}
}
ljh[i+2][j+1][cnt+1]--;
ljh[i+2][j+1][cnt+1]=(ljh[i+2][j+1][cnt+1]%mod+mod);
for(int t=1;t<=cnt+1;t++)
ljh[i+2][j+1][t]=1ll*ljh[i+2][j+1][t]*invw[4]%mod;
}else {
cnt1++;
for(int t=1;t<=cnt+1;t++) a[cnt1][t]=ljh[i][j][t];
for(int k=0;k<8;k++) {
int nx=i-dx[k],ny=j-dy[k];
if((k==4)||(!check(nx,ny))) continue;
for(int t=1;t<=cnt+1;t++){
a[cnt1][t]-=1l*ljh[nx][ny][t]*w[k]%mod;
a[cnt1][t]=(a[cnt1][t]%mod+mod)%mod;
}
}
a[cnt1][cnt+1]--;
a[cnt1][cnt+1]=(a[cnt1][cnt+1]%mod+mod)%mod;
a[cnt1][cnt+1]=-a[cnt1][cnt+1];
a[cnt1][cnt+1]=(a[cnt1][cnt+1]%mod+mod)%mod;
}
}
}
Gauss(cnt);
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
for(int t=1;t<=cnt;t++)
ans[gett(i,j)]=(1ll*ans[gett(i,j)]+1ll*a[t][cnt+1]*ljh[i][j][t]%mod)%mod;
ans[gett(i,j)]=(1ll*ans[gett(i,j)]+1ll*ljh[i][j][cnt+1])%mod;
}
}
}
void init(){
scanf("%d%d",&n,&m);
for(int i=0;i<8;i++) {
scanf("%d",&w[i]);
sum+=w[i];
}
sum=inv(sum);
for(int i=0;i<8;i++) {
w[i]=1ll*w[i] *sum%mod;
invw[i]=inv(w[i]);
}
}
int main() {
freopen("chess.in","r",stdin);
freopen("chess.out","w",stdout);
init();
work();
int Q;scanf("%d",&Q); while(Q--) {
int x,y; scanf("%d%d",&x,&y);
printf("%d\n",ans[gett(x,y)]);
}
}