Chess【矩阵快速幂】


题目大意

给你一张nxm的棋盘格,你可以在格点上下棋。
有三种选择:
op=0 棋子是车,横着走或竖着走任意步
op=1 棋子是马,走日字
op=2 棋子是象,走2x2的格子的对角
有多组数据。每一组数据给你一个选择,初始出发地点(c,d),问你走e步后不同的路径有多少条。

范围:
nxm<=100,e<=1e9

正解

把每个格点(坐标)化成一维的,建立一个size为nm x nm的矩阵,其中的元素aij表示从i点走到j点长度为1的路径条数(三种op分开考虑)
矩阵的乘法中,如果C=AxB,那么C.a[i][j]=\(\sum_{k=1}\)A.a[i][k]*B.[k][j]
可以看成i到j需要经过一个中转点k,这样i到j的路径长度就由1变成了2.
在本题中,因此可以用矩阵快速幂求得走e步之后的矩阵(即知道了e步后任意点之间的路径条数),答案=从初始出发点对应的编号到其他所有点的路径条数之和

//chess   
//引入矩阵Mi  aij:到达aij的长度为i的路径方案数   sum(aij):长度为i的总方案数

#include
#define ll long long
using namespace std;
const int mod = 19260817,N = 105;
ll t,n,m,c,d,e,op;
int dir_0[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
int dir_1[8][2]={{2,1},{2,-1},{-2,1},{-2,-1},{1,2},{1,-2},{-1,2},{-1,-2}};
int dir_2[4][2]={{2,-2},{2,2},{-2,2},{-2,-2}};

struct Matrix{
	int n,m;
	ll a[105][105];
	
	inline void init(int _n,int _m){
		n=_n;
		m=_m;
		memset(a,0,sizeof(a));
	} 
	
	inline void init_e(){
		for(int i=1;i<=n;i++) a[i][i]=1;
	}
	
}S;

int pos(int x,int y){
	return y+(x-1)*m;
}

Matrix mul(Matrix A,Matrix B){
		Matrix C;
		C.init(A.n,B.m);
//		puts("A");A.print();puts("");
//		puts("B");B.print();puts("");
		for(int i=1;i<=A.n;i++){
			for(int j=1;j<=B.m;j++){
				for(int k=1;k<=A.m;k++){
					C.a[i][j]=(C.a[i][j]+1ll*A.a[i][k]*B.a[k][j]%mod)%mod;
				}
			}
		}
//		puts("C");C.print();puts("");
		return C;
	}

Matrix qpow(Matrix A,ll p){
		Matrix ans; ans.init(A.m,A.m); ans.init_e();
		while(p){
			if(p%2==1) ans=mul(ans,A);
			A=mul(A,A);
			p>>=1;
		}
		return ans;
	}

void init_0(){
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			int now=pos(i,j);
			for(int k=0;k<4;k++){
				for(int tt=1;;tt++){
					int x=i+tt*dir_0[k][0];
					int y=j+tt*dir_0[k][1];
					if(x<1||y<1||x>n||y>m) break;
					int nex=pos(x,y);
					S.a[now][nex]++;
				}
				
			}
		}
	}
}

void init_1(){
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			int now=pos(i,j);
			for(int k=0;k<8;k++){
				int x=i+dir_1[k][0];
				int y=j+dir_1[k][1];
				if(x<1||y<1||x>n||y>m) continue;
				int nex=pos(x,y);
				S.a[now][nex]++;
			}
		}
	}
}

void init_2(){
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			int now=pos(i,j);
			for(int k=0;k<4;k++){
				int x=i+dir_2[k][0];
				int y=j+dir_2[k][1];
				if(x<1||y<1||x>n||y>m) continue;
				int nex=pos(x,y);
				S.a[now][nex]++;
			}
		}
	}
}

int main(){
	cin>>t;
	while(t--){
		scanf("%d%d%d%d%d%d",&op,&n,&m,&c,&d,&e);
		S.init(n*m,n*m);
		if(op==0) init_0();
		if(op==1) init_1();
		if(op==2) init_2();
		
		S=qpow(S,e);
		
		int st=pos(c,d);
		ll ans=0;
		for(int i=1;i<=m*n;i++){
			ans=(ans+S.a[st][i])%mod;
		}
		printf("%lld\n",ans);
	}
	return 0;
}