[省选联考 2020 A 卷] 组合数问题

题目描述

给定整数 $n$ , $x$ , $p$ ,一个 $m$ 次多项式 $f(k) = a_0 + a_1k + a_2k^2 + \cdots + a_mk^m$ ,计算

$$\left(\sum_{k=0}^{n}f(k)\times x^k\times \binom{n}{k}\right)\bmod p $$

$1\le n, x, p \le 10^9, 0\le a_i\le 10^9, 0\le m \le \min(n,1000)$

题解

推式子

$$\begin{aligned} &\quad\sum_{k=0}^nf(k)x^k\binom{n}{k}\\ &=\sum_{k=0}^n\sum_{i=0}^ma_ik^ix^k\binom{n}{k}\\ &=\sum_{i=0}^ma_i\sum_{k=0}^nk^ix^k\binom{n}{k}\\ \end{aligned} $$

考虑生成函数

$$\begin{aligned} (1+x)^n&=\sum_{k=0}^nx^k\binom{n}{k}\\ ((1+x)^n)^{(i)}&=\sum_{k}x^k\binom{n}{k+i}(k+i)^{\underline{i}}\\ x^in^{\underline{n}}(1+x)^{n-i}&=\sum_kx^k\binom{n}{k}k^{\underline{i}} \end{aligned} $$

有结论

$$x^n=\sum_{k=0}^{n}\begin{Bmatrix}n\\k\end{Bmatrix}x^{\underline{k}} $$

代入

$$\begin{aligned} &\quad\sum_{i=0}^ma_i\sum_{k=0}^nk^ix^k\binom{n}{k}\\ &=\sum_{i=0}^ma_i\sum_{k=0}^{n}\sum_{j=0}^{i}\begin{Bmatrix}i\\j\end{Bmatrix}k^{\underline{j}}x^k\binom{n}{k}\\ &=\sum_{i=0}^ma_i\sum\limits_{j=0}^{i}\begin{Bmatrix}i\\j\end{Bmatrix}x^jn^{\underline{j}}(1+x)^{n-j} \end{aligned} $$

预处理斯特林数、特判 $a_0$ $\mathcal{O}(m^2)$

也有组合意义推法。

代码

const int N = 1010;

inline ll Read() {
	ll x = 0, f = 1;
	char c = getchar();
	while (c != '-' && (c < '0' || c > '9')) c = getchar();
	if (c == '-') f = -f, c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
	return x * f;
}

namespace Main {
	int n, x, mod, m;
	int a[N];
	int ans;
	int S[N][N];
	int add (int x, int y) { return x + y > mod? x + y - mod: x + y; }
	int dec (int x, int y) { return x - y < 0? x - y + mod: x - y; }
	int mul (int x, int y) { return 1ll * x * y % mod; }
	int qpow (int a, ll b) {
		int ans = 1;
		for (; b; b >>= 1, a = mul(a, a))
			if (b & 1) ans = mul(ans, a);
		return ans;
	}
	int main () {
		n = Read(), x = Read(), mod = Read(), m = Read();
		for (int i = 0; i <= m; i++) a[i] = Read();
		S[1][1] = 1;
		for (int i = 2; i <= m; i++)
			for (int j = 1; j <= i; j++)
				S[i][j] = add(mul(S[i - 1][j], j), S[i - 1][j - 1]);
		ans = mul(a[0], qpow((x + 1) % mod, n));
		for (int j = 1; j <= m; j++) {
			int pw = mul (qpow(x % mod, j), qpow((1 + x) % mod, n - j)), sum = 0;
			for (int i = 0; i < j; i++) pw = mul(pw, n - i);
			for (int i = j; i <= m; i++) sum = add(sum, mul(S[i][j], a[i]));
			ans = add(ans, mul(pw, sum));
		}
		printf ("%d\n", ans);
		return 0;
	}
}

int main () {
	string str = "";
//	freopen((str + ".in").c_str(), "r", stdin);
//	freopen((str + ".out").c_str(), "w", stdout);
	Main::main();
	return 0;
}
EOF

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。

博客信息

作者
Jayun
时间
2024-02-23 10:25:17
博客类型