【2020全国统一省选】组合数问题 题解

题目大意

  求

  其中 $n,x,p$ 为给定整数,$f(k)$ 为给定多项式 $f(k)=\sum_{i=0}^m a_ik^i$ 。

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

题解

  转了一圈,这题的推法似乎多种多样啊。。。(虽然本质相同
  就记录一个我觉得比较好的吧。

  核心思路就是 $k^i\binom{n}{k}$ 写成下降幂多项式,然后发现有奇效。

  设 $f(k)=\sum_{i=0}^m a_ik^i$ 转化成下降幂多项式为

  代入原式有

  这个东西 $O(m)$ 循环一遍就好了,$(x+1)^{n-i}$ 可以预处理也可以快速幂。

  至于 $b_i$ 的求法,也就是多项式转下降幂多项式,根据

  (其中 $S(i,j)$ 表示第二类斯特林数)可得

  因此预处理第二类斯特林数,然后 $b_j= \sum_{i=j}^m a_iS(i,j)$ 即可。

代码

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
#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;

typedef long long LL;

const int maxm=1005;

LL n,x,mo,a[maxm];
int m;

LL S[maxm][maxm];
void S_pre(int n)
{
fo(i,0,m)
{
fo(j,1,i-1) S[i][j]=(S[i-1][j-1]+j*S[i-1][j])%mo;
S[i][i]=1;
}
}

LL b[maxm];
void FFP()
{
fo(i,0,m)
fo(j,i,m) (b[i]+=a[j]*S[j][i])%=mo;
}

LL Pow(LL x,LL y)
{
LL re=1;
for(; y; y>>=1, x=x*x%mo) if (y&1) re=re*x%mo;
return re;
}

int main()
{
freopen("problem.in","r",stdin);
freopen("problem.out","w",stdout);

scanf("%lld %lld %lld %d",&n,&x,&mo,&m);
fo(i,0,m) scanf("%lld",&a[i]);

S_pre(m);
FFP();

LL ndown=1, xpow=1, ans=0;
fo(i,0,m)
{
(ans+=b[i]*xpow%mo*ndown%mo*Pow(x+1,n-i))%=mo;
(xpow*=x)%=mo;
(ndown*=n-i)%=mo;
}

printf("%lld\n",ans);
}