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

Description

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

的值。其中 $n$, $x$, $p$ 为给定的整数,$f(k)$ 为给定的一个 $m$ 次多项式 $f(k) = a_0 + a_1k + a_2k^2 + \cdots + a_mk^m$。$\binom{n}{k}$ 为组合数,其值为 $\binom{n}{k} = \frac{n!}{k!(n-k)!}$。

Solution

手玩。

考虑 $m=0$ 的情况。
$$
a_0\left(\sum_{k=0}^{n}x^k\times \binom{n}{k}\right)\bmod p=(a_0(x+1)^{n}) \bmod p
$$
然后考虑 $m=1$ 的情况。
$$
a_1\left(\sum_{k=0}^{n}k\times x^k\times \binom{n}{k}\right)\bmod p
$$

$$
=a_1\left(\sum_{k=0}^{n}k\times x^k\times \dfrac{n!}{k!(n-k)!}\right)\bmod p
$$

$$
=a_1\left(\sum_{k=0}^{n}x^k\times \dfrac{n!}{k!(n-k-1)!}\right)\bmod p
$$

$$
=a_1\times n\left(\sum_{k=1}^{n}x^k\times \dfrac{(n-1)!}{k!(n-k-1)!}\right)\bmod p
$$

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

不难发现这是二项式定理的形式。
$$
=a_1\times n\times x\times (x+1)^{n}\bmod p=a_1\times g_n(1)
$$
同样,考虑 $m=2$ 的情况:
$$
a_2\left(\sum_{k=0}^{n}k^2\times x^k\times \binom{n}{k}\right)\bmod p
$$

$$
=a_2\left(\sum_{k=0}^{n}k\times x\times \binom{n}{k}+\sum_{k=0}^n k(k-1)\times x\times \binom{n}{k}\right)\bmod p
$$

$$
=a_2\times g_n(1)+a_2\times n(n-1)x^2\times (x+1)^{n-1}=a_2(g_n(1)+g_n(2))
$$

关于 $g_n$ 的递推是显然。现在我们需要找到关于 $n^k=\sum\limits_{i=1}^k b_{k,i} \dfrac{n!}{(n-i)!}$ 的系数 $b$。这个是可以 $O(m^2)$ 递推的。

总复杂度 $O(m+m^2)$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define maxn 1005
#define put() putchar('\n')
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
using namespace std;
inline void read(int &x){
int f=1;x=0;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
x*=f;
}
namespace Debug{
Tp void _debug(char* f,Ty t){cerr<<f<<'='<<t<<endl;}
Ts void _debug(char* f,Ty x,Ar... y){while(*f!=',') cerr<<*f++;cerr<<'='<<x<<",";_debug(f+1,y...);}
Tp ostream& operator<<(ostream& os,vector<Ty>& V){os<<"[";for(auto& vv:V) os<<vv<<",";os<<"]";return os;}
#define gdb(...) _debug((char*)#__VA_ARGS__,__VA_ARGS__)
}using namespace Debug;
int g[maxn],n,x,mod,m,a[maxn];
inline int power(int x,int y) {
int sum=1;
while (y) {
if (y&1) sum=sum*x%mod;
x=x*x%mod;y>>=1;
}
return sum;
}
int ans,b[maxn][maxn],f[maxn];
signed main(void){
int i,j,sum1,sum2;
read(n);read(x);read(mod);read(m);
for (i=0;i<=m;i++) read(a[i]);
sum1=1,sum2=1;
for (i=0;i<=m;i++) {
g[i]=sum1*sum2%mod*power(x+1,n-i)%mod;
sum1=sum1*x%mod;sum2=sum2*(n-i)%mod;
}
//预处理
//其实可以不需要快速幂
f[0]=g[0];b[1][1]=1;f[1]=g[1];
for (i=2;i<=m;i++) {
b[i][1]=(-b[i-1][1]*(i-1)%mod+mod)%mod;
for (j=1;j<i;j++) {
b[i][j+1]=(b[i-1][j]-b[i-1][j+1]*(i-1)%mod+mod)%mod;
}
for (j=1;j<i;j++) f[i]=(f[i]+f[j]*(-b[i][j])%mod+mod)%mod;
f[i]=(f[i]+g[i])%mod;
}
//计算系数 b
for (i=0;i<=m;i++) ans=(ans+f[i]*a[i])%mod;
printf("%lld",ans);
return 0;
}