洛谷 P7481 梦现时刻 题解

给定 \(n,m\) ,保证 \(m\le n\),令 \(F(a,b)=\sum_{i=0}^{b}\binom{b}{i}\binom{n-i}{a}\)

\(\bigoplus_{a=1}^{m}\bigoplus_{b=1}^{m}(F(a,b) \bmod 998244353)\)

其中 \(\oplus\) 表示异或运算。

\(m\le 5000,n\le 10^9\)

稍微分析一下,我们希望把这个 \(F(a,b)\) 用若干个 \(F(a\pm 1, b\pm 1)\) 表示出来,这样就能递推了。

先把 \(F(a,b)\) 拆成 \(F(a,b)=[{b-1\choose i}+{b-1\choose i-1}]{n-i\choose a}\),这样我们发现括号里的第一项与右边这一项乘起来恰好就是 \(F(a,b-1)\)。但是我们还剩下一个 \({b-1\choose i-1}\) 没有处理。由于它有一个 \(i-1\),所以我们想要右边也出现一个 \(i-1\),于是将右边拆成 \({n-i+1\choose a+1}-{n-i\choose a+1}\)

于是你发现,有 \(F(a,b)=\sum_i [{b - 1 \choose i}+{b-1\choose i-1}][{n-i+1 \choose a+1}-{n-i \choose a+1}]\)。不妨从左到右标成 \(A,B,C,D\),我们要求的 \(F(a,b)\) 就等于 \((A+B)(C-D)\),再分析一下发现有 \(F(a,b-1)=AC-AD,F(a+1,b-1)=AD=BC,F(a+1,b)=AD+BD\),于是凑一下系数就得到:

\[\boxed{F(a,b)=F(a,b-1)-F(a+1,b)+2F(a+1,b-1)} \]

于是就可以递推了。时间复杂度 \(O(m^2)\)

const int MAXN = 5e3 + 5, mod = 998244353;
int n, m, f[MAXN][MAXN], C[MAXN][MAXN], T[MAXN]; // T[i] = (n-i \choose m)

int quickpow(int a, int b) {
	int ret = 1;
	while (b) {
		if (b & 1) ret = ret * a % mod;
		a = a * a % mod; b >>= 1;
	}
	return ret;
}

void work() {
	cin >> n >> m;
	f[1][0] = n;
	for (int a = 2; a <= m; ++a) {
		f[a][0] = f[a - 1][0] * (n - a + 1) % mod * quickpow(a, mod - 2) % mod;
	}
	for (int i = 0; i <= m; ++i) 
		C[i][0] = 1;
	for (int i = 1; i <= m; ++i) {
		for (int j = 1; j <= m; ++j) {
			C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
		}
	}
	int facm = 1; T[0] = 1;
	for (int i = 1; i <= m; ++i) {
		facm = facm * i % mod;
		T[0] = T[0] * (n - m + i) % mod;
	}
	T[0] = T[0] * quickpow(facm, mod - 2) % mod;
	for (int i = 1; i <= m; ++i) {
		T[i] = T[i - 1] * (n - i + 1 - m) % mod * quickpow(n - i + 1, mod - 2) % mod;
	}
	for (int b = 1; b <= m; ++b) {
		for (int i = 0; i <= b; ++i) {
			f[m][b] = (f[m][b] + C[b][i] * T[i] % mod) % mod;
		}
	}
	for (int b = 1; b <= m; ++b) {
		for (int a = m - 1; a; --a) {
			f[a][b] = (f[a][b - 1] - f[a + 1][b] + 2 * f[a + 1][b - 1]) % mod;
			f[a][b] = (f[a][b] + mod) % mod;
		}
	}
	int ans = 0;
	for (int a = 1; a <= m; ++a) {
		for (int b = 1; b <= m; ++b) {
			ans ^= f[a][b];
		}
	}
	cout << ans << endl;
}

/*
g++ -o LG7481 LG7481.cpp -O2 -std=c++14 -Wall -DLOCAL_TEST && LG7481.exe < test.in
*/
posted @ 2025-11-10 17:20  小蛐蛐awa  阅读(8)  评论(0)    收藏  举报