【洛谷 P6620 [2020 年联考 A 卷] 组合数问题】【组合数学】

题意

计算 ( ∑ k = 0 n f ( k ) x k ( n k ) )   m o d   p (\sum_{k=0}^nf(k)x^k\binom{n}{k})\bmod p (k=0nf(k)xk(kn))modp

其中 f ( k ) f(k) f(k)是一个 m m m次多项式 a 0 + a 1 k + ⋯ + a m k m a_0+a_1k+\cdots+a_mk^m a0+a1k++amkm
n , x , p , a i ≤ 1 0 9 , m ≤ 1000 n,x,p,a_i\le 10^9, m\le 1000 n,x,p,ai109,m1000

分析

注意到 m m m很小,考虑把 m m m放前面,有 ∑ k = 0 n ( ∑ i = 0 m a i k i ) x k ( n k ) = ∑ i = 0 m a i ∑ k = 0 n k i x k ( n k ) \sum_{k=0}^n(\sum_{i=0}^ma_ik^i)x^k\binom{n}{k}=\sum_{i=0}^ma_i\sum_{k=0}^nk^ix^k\binom{n}{k} k=0n(i=0maiki)xk(kn)=i=0maik=0nkixk(kn)

g ( x ) = ( x + 1 ) n g(x)=(x+1)^n g(x)=(x+1)n,容易发现 g ( x ) = ∑ k = 0 n x k ( n k ) , x g ′ ( x ) = ∑ k = 0 n k x k ( n k ) g(x)=\sum_{k=0}^nx^k\binom{n}{k},\quad xg'(x)=\sum_{k=0}^nkx^k\binom{n}{k} g(x)=k=0nxk(kn),xg(x)=k=0nkxk(kn)

同理可知 ∑ k = 0 n k i x k ( n k ) \sum_{k=0}^nk^ix^k\binom{n}{k} k=0nkixk(kn)

相当于对 g ( x ) g(x) g(x) i i i次先求导再乘 x x x后得到的多项式。若不把 ( x + 1 ) n (x+1)^n (x+1)n展开,则每次求导只会增加一项。只需要维护每一项前的系数就好了。
时间复杂度 O ( m 2 log ⁡ n ) O(m^2\log n) O(m2logn) O ( m 2 ) O(m^2) O(m2)

代码

#include
using namespace std;

typedef long long LL;

const int N = 1005;

int n, x, MOD, m, a[N], f[N], g[N];

int ksm(int x, int y)
{
	int ans = 1;
	while (y)
	{
		if (y & 1) ans = (LL)ans * x % MOD;
		x = (LL)x * x % MOD; y >>= 1;
	}
	return ans;
}

int main()
{
	scanf("%d%d%d%d", &n, &x, &MOD, &m);
	for (int i = 0; i <= m; i++) scanf("%d", &a[i]);
	f[0] = 1;
	int ans = 0;
	for (int i = 0; i <= m; i++)
	{
		for (int j = 0; j <= i; j++)
			(ans += (LL)a[i] * f[j] % MOD * ksm(x, j) % MOD * ksm(x + 1, n - j) % MOD) %= MOD;
		memset(g, 0, sizeof(g));
		for (int j = 0; j <= i; j++)
		{
			(g[j] += (LL)f[j] * j % MOD) %= MOD;
			(g[j + 1] += (LL)f[j] * (n - j) % MOD) %= MOD;
		}
		for (int j = 0; j <= i + 1; j++) f[j] = g[j];
	}
	printf("%d\n", ans);
	return 0;
}

你可能感兴趣的:(组合数学)