[LOJ #3533] NOI2021 路径交点

2021/7/31 6:09:26

本文主要是介绍[LOJ #3533] NOI2021 路径交点,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

[LOJ #3533] NOI2021 路径交点

这题反映出来的就是菜吧

当时就是没想出来。

我们可以想到的一点就是,路径的这个交点个数,其实就是逆序对个数。于是我们考虑 \(K = 2\) 的情况,就是这一层边的临接矩阵的 \(\text{Det}\)。

我们考虑一个事情就是假如一层的奇数答案是 \(f_i\),偶数是 \(g_i\),那么就有 \((g_i-f_i)\times(g_{i+1}-f_{i+1})\) 就是答案。也就是两个答案相乘就得到了两层的答案。

然后我们就解决了 \(n[i]=n[1]\) 的情况了。

结合一个很牛的东西就是 \(|A\times B|=|A|\times |B|\)。

我们考虑每次直接把矩阵相乘,随后的逆序对个数其实和每次分开算的奇偶性是一样的,我们只要最后算出来 \(a_{x,y}\) 表示把这个 \((1,x)\) 点跑到 \((k,y)\) 的路径条数的数量,然后求 \(Det\) 即可。

#include <bits/stdc++.h>
const int N = 105, P = 205;
using std::cin;
using std::cout;
const int mod = 998244353;
inline int Mod(int x) {
	if (x >= mod) {
		return x - mod;
	}
	else if (x < 0) {
		return x + mod;
	}
	else {
		return x;
	}
}
int T, n[N], m[N];
inline int ksm(int x, int y) {
	int res = 1;
	for ( ; y; y /= 2, x = 1LL * x * x % mod) {
		if (y & 1) {
			res = 1LL * res * x % mod;
		}
	}
	return res;
}
struct Matrix {
	int row, col, vals[P][P];
	int* operator [] (int x) {
		return vals[x];
	}
	void init(int SZ) {
		for (int i = 1; i <= SZ; ++i) {
			vals[i][i] = 1;
		}
	}
	Matrix(int R = 0, int C = 0) {
		memset(vals, 0, sizeof vals);
		row = R;
		col = C;
	}
	Matrix operator * (Matrix &a) {
		Matrix res;
		for (int i = 1; i <= row; ++i) {
			for (int k = 1; k <= col; ++k) {
				for (int j = 1; j <= a.col; ++j) {
					res[i][j] = Mod(res[i][j] + 1LL * vals[i][k] * a[k][j]);
				}
			}
		}
		res.row = row;
		res.col = a.col;
		return res;
	}
};
void print(Matrix &a) {
	cout << a.row << ' ' << a.col << '\n';
	for (int i = 1; i <= a.row; ++i) {
		for (int j = 1; j <= a.col; ++j) {
			cout << a[i][j] << " \n"[j == a.col];
		}
	}
}
int Det(Matrix a) {
	int res = 1, kk = 0;
	for (int i = 1; i <= a.col; ++i) {
		int pos;
		for (pos = i; pos <= a.col; ++pos) {
			if (a[pos][i]) {
				break;
			}
		}
		if (pos == a.col + 1) {
			return 0;
		}
		kk ^= (pos != i);
		std::swap(a.vals[pos], a.vals[i]);
		int inv = ksm(a[i][i], mod - 2);
		for (int j = i + 1; j <= a.col; ++j) {
			int l = 1LL * a[j][i] * inv % mod;
			for (int k = i; k <= a.col; ++k) {
				a[j][k] = Mod(a[j][k] - 1LL * l * a[i][k] % mod);
			}
		}
		res = 1LL * res * a[i][i] % mod;
	}
	return kk ? Mod(-res) : res;
}
void solve() {
	int K;
	cin >> K;
	for (int i = 1; i <= K; ++i) {
		cin >> n[i];
	}
	for (int i = 1; i < K; ++i) {
		cin >> m[i];
	}
	Matrix ans(n[1], n[1]);
	ans.init(n[1]);
	//print(ans);
	for (int i = 1; i < K; ++i) {
		Matrix g(n[i], n[i + 1]);
		for (int j = 1, u, v; j <= m[i]; ++j) {
			cin >> u >> v;
			g[u][v] = 1;
		}
		ans = ans * g;
	//	print(ans);
	}
	cout << Det(ans) << '\n';
}
int main() {
	freopen("xpath.in", "r", stdin);
	freopen("xpath.out", "w", stdout);
	std::ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> T;
	while (T--) {
		solve();
	}
	return 0;
}


这篇关于[LOJ #3533] NOI2021 路径交点的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程