[洛谷P5107]能量采集

题目大意:有一张$n(nleqslant50)$个点$m(mleqslant n(n-1))$条边的有向图,每个点还有一个自环,每个点有一个权值。每一秒钟,每个点的权值会等分成出边个数,流向出边。$q(qleqslant5 imes10^4)$次询问,每次问$t$秒时每个点的权值,只需要输出异或和

题解:矩阵快速幂,可以构造出转移矩阵,发现直接做的复杂度是$O(qn^3log_2t)$,不可以通过。

然后预处理转移矩阵的$2^i$次幂,就可以$O(n^2)$完成一次转移(向量乘矩阵),这样复杂度是$O(qn^2log_2t)$,看起来不可以通过本题,但其实也可以了。

题解中说是把预处理中的二进制改成$k$进制,这样复杂度是$O(n^3klog_kt+qn^2log_kt)$

卡点:

C++ Code:

#include <cstdio>
#include <cctype>
namespace __IO {
	namespace R {
		int x, ch;
		inline int read() {
			while (isspace(ch = getchar())) ;
			for (x = ch & 15; isdigit(ch = getchar()); ) x = x * 10 + (ch & 15);
			return x;
		}
	}
}
using __IO::R::read;

#define maxn 50
const int mod = 998244353;
namespace Math {
	inline int pw(int base, int p) {
		static int res;
		for (res = 1; p; p >>= 1, base = static_cast<long long> (base) * base % mod) if (p & 1) res = static_cast<long long> (res) * base % mod;
		return res;
	}
	inline int inv(int x) { return pw(x, mod - 2); }
}

struct Matrix {
#define N 50
	int n, m;
	int s[N][N];

	inline Matrix operator * (const Matrix &rhs) {
		Matrix res;
		res.n = n, res.m = rhs.m;
		for (register int i = 0; i < n; ++i) {
			for (register int j = 0; j < rhs.m; ++j) {
				static long long t; t = 0;
				for (register int k = 0; k < m; ++k) t += static_cast<long long> (s[i][k]) * rhs.s[k][j] % mod;
				res.s[i][j] = t % mod;
			}
		}
		return res;
	}
#undef N
} I, base[32], ans;

int n, m, q;
int oud[maxn];
int main() {
	n = read(), m = read(), q = read();
	for (int i = 0; i < n; ++i) I.s[0][i] = read(), base[0].s[i][i] = 1, oud[i] = 1;
	I.n = 1, I.m = n;
	while (m --> 0) {
		int a = read() - 1, b = read() - 1;
		++base[0].s[a][b];
		++oud[a];
	}
	base[0].n = base[0].m = n;
	for (int i = 0, t; i < n; ++i) {
		t = Math::inv(oud[i]);
		for (int j = 0; j < n; ++j) base[0].s[i][j] = static_cast<long long> (t) * base[0].s[i][j] % mod;
	}
	for (int i = 1; i < 32; ++i) base[i] = base[i - 1] * base[i - 1];
	while (q --> 0) {
		Matrix res = I;
		for (int i = read(); i; i &= i - 1) res = res * base[__builtin_ctz(i)];
		int ans = 0;
		for (int i = 0; i < n; ++i) ans ^= res.s[0][i];
		printf("%d
", ans % mod);
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/Memory-of-winter/p/10258704.html