【LOJ3080】「2019 集训队互测 Day 5」国际象棋

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/89786126

【题目链接】

【思路要点】

  • 不难得到 O ( N 3 M 3 ) O(N^3M^3) 的暴力高斯消元做法。
  • 将前 2 2 行,第 1 1 列的变量作为主元,从上到下、从左到右依次考虑变量 ( i , j ) (i,j) 的转移式。
  • 可以发现,涉及的变量中只有 ( i + 2 , j + 1 ) (i+2,j+1) 未被主元线性表示,因而可以由该转移得到 ( i + 2 , j + 1 ) (i+2,j+1) 关于主元的线性表示,若 ( i + 2 , j + 1 ) (i+2,j+1) 在棋盘外,那么就可以得到一个关于主元的方程。
  • 最终将得到 O ( N + M ) O(N+M) 个变量和等量的方程,采用高斯消元即可。
  • 时间复杂度 O ( ( N + M ) 3 ) O((N+M)^3)

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 205;
const int MAXP = 605;
const int P = 998244353;
const int dx[8] = {-2, -1, 1, 2, 2, 1, -1, -2};
const int dy[8] = {-1, -2, -2, -1, 1, 2, 2, 1};
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
int power(int x, int y) {
	if (y == 0) return 1;
	int tmp = power(x, y / 2);
	if (y % 2 == 0) return 1ll * tmp * tmp % P;
	else return 1ll * tmp * tmp % P * x % P;
}
int n, m, q, cnt, tot, sum;
int coef[MAXN][MAXN][MAXP];
int p[8], a[MAXP][MAXP], res[MAXP];
void update(int &x, int y) {
	x += y;
	if (x >= P) x -= P;
}
void gauss(int n) {
	for (int i = 1; i <= n; i++) {
		for (int j = i; j <= n; j++)
			if (a[j][i] != 0) {
				swap(a[i], a[j]);
				break;
			}
		if (a[i][i] == 0) {
			assert(false);
			return;
		}
		int inv = power(a[i][i], P - 2);
		for (int j = i + 1; j <= n; j++) {
			int tmp = 1ll * a[j][i] * inv % P;
			for (int k = i; k <= n + 1; k++)
				a[j][k] = (a[j][k] - 1ll * a[i][k] * tmp % P + P) % P;
		}
	}
	for (int i = n; i >= 1; i--) {
		res[i] = 1ll * power(a[i][i], P - 2) * a[i][n + 1] % P;
		for (int j = 1; j <= i - 1; j++)
			if (a[j][i]) update(a[j][n + 1], P - 1ll * res[i] * a[j][i] % P);
	}
}
int main() {
	read(n), read(m);
	for (int i = 0; i <= 7; i++)
		read(p[i]), sum += p[i];
	sum = power(sum, P - 2);
	for (int i = 0; i <= 7; i++)
		p[i] = 1ll * p[i] * sum % P;
	for (int i = 1; i <= 2; i++)
	for (int j = 1; j <= m; j++)
		cnt++, coef[i][j][cnt] = 1;
	for (int i = 3; i <= n; i++)
		cnt++, coef[i][1][cnt] = 1;
	for (int i = 1; i <= n; i++)
	for (int j = 1; j <= m; j++) {
		if (i + 2 <= n && j + 1 <= m) {
			coef[i + 2][j + 1][cnt + 1] = P - 1;
			for (int k = 1; k <= cnt + 1; k++)
				update(coef[i + 2][j + 1][k], coef[i][j][k]);
			for (int d = 0; d <= 7; d++)
				if (d != 4 && i + dx[d] >= 1 && i + dx[d] <= n && j + dy[d] >= 1 && j + dy[d] <= m) {
					for (int k = 1; k <= cnt + 1; k++)
						update(coef[i + 2][j + 1][k], P - 1ll * p[d] * coef[i + dx[d]][j + dy[d]][k] % P);
				}
			int inv = power(p[4], P - 2);
			for (int k = 1; k <= cnt + 1; k++)
				coef[i + 2][j + 1][k] = 1ll * coef[i + 2][j + 1][k] * inv % P;
		} else {
			a[++tot][cnt + 1] = P - 1;
			for (int k = 1; k <= cnt + 1; k++)
				update(a[tot][k], coef[i][j][k]);
			for (int d = 0; d <= 7; d++)
				if (i + dx[d] >= 1 && i + dx[d] <= n && j + dy[d] >= 1 && j + dy[d] <= m) {
					for (int k = 1; k <= cnt + 1; k++)
						update(a[tot][k], P - 1ll * p[d] * coef[i + dx[d]][j + dy[d]][k] % P);
				}
			a[tot][cnt + 1] = (P - a[tot][cnt + 1]) % P;
		}	
	}
	gauss(cnt), read(q);
	for (int i = 1; i <= q; i++) {
		int x, y; read(x), read(y);
		int ans = coef[x][y][cnt + 1];
		for (int j = 1; j <= cnt; j++)
			update(ans, 1ll * res[j] * coef[x][y][j] % P);
		writeln(ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39972971/article/details/89786126