P6620 [省选联考 2020 A 卷] 组合数问题
P6620 [省选联考 2020 A 卷] 组合数问题
分析
我们考虑将式子。
\[\sum_{k=0}^{n}f(k)*x^k*\binom{n}{k}
\]
其中f(k)是一个多项式,我们考虑其中某一个单项式
\[k^i*\binom{n}{k}*x^k
\]
这里,有一个非常常用的小技巧。
\[x^{\underline{m}}*\binom{n}{k} = \binom{n-m}{k-m}n^{\underline{m}}
\]
一次我们考虑将\(f(k)=\sum_{i=0}^{m}a_ik^i\)转化为下降幂多项式\(f(k)=\sum_{i=0}^{m}b_ix^{\underline{i}}\)
则式子就变为了。
\[\sum_{k=0}^{n}\sum_{i=0}^{m}b_ik^{\underline{i}}*x^k*\binom{n}{k} = \sum_{i=0}^{m}b_in^{\underline{i}}\sum_{k=0}^{n}\binom{n-i}{k-i}x^k
\]
此时我们将后面进行二项式展开
\[\sum_{i=0}^{m}b_in^{\underline{i}}\sum_{k=0}^{n-i}\binom{n-i}{k}x^{k+i} = \sum_{i=0}^{m}b_in^{\underline{i}}x^i(x+1)^{n-i}
\]
接下来就是最后一个问题了,如何将一个普通多项式转化为下降沿多项式。
这个问题有\(O(nlogn)\)的解法,但是本题不用这么麻烦,可以直接用\(O(n^2)\)的方法。
我们来推导一下。
我们知道
\[x^n=\sum_{i=0}^{n}S(n,i)x^{\underline{i}}
\]
因此,当我们带入并交换求和次序时,可以得到。
\[\sum_{i=0}^{m}a_ik^i = \sum_{i=0}^{m}a_i\sum_{j=0}^{i}S(i,j)k^{\underline{j}}
\\=\sum_{i=0}^{m}k^{\underline{i}}\sum_{j=i}^{m}S(j,i)a_j
\]
也就是说
\[b_i = \sum_{j=i}^{m}S(j,i)a_j
\]
结束啦。
AC_code
#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(false); cin.tie(0), cout.tie(0)
using namespace std;
const int N = 1010;
int S[N][N];
int n,x,p,m;
void init(int n)
{
S[0][0] = 1;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
S[i][j] = (1ll*S[i-1][j-1] + 1ll*j*S[i-1][j]%p)%p;
}
int ksm(int a,int b)
{
int res = 1;
while(b)
{
if(b&1) res = 1ll*res*a%p;
a = 1ll*a*a%p;
b >>= 1;
}
return res;
}
int main()
{
ios;
cin>>n>>x>>p>>m;
init(m);
vector<int> a(m+1),b(m+1),xpow(m+1),fact(m+1),x1pow(m+1);
fact[0] = xpow[0] = 1;
for(int i=1;i<=m;i++)
{
fact[i] = 1ll*fact[i-1]*(n-i+1)%p;
xpow[i] = 1ll*xpow[i-1]*x%p;
}
x1pow[m] = ksm((x+1)%p,n-m);
for(int i=m-1;i>=0;i--)
x1pow[i] = 1ll*x1pow[i+1]*(x+1)%p;
for(int i=0;i<=m;i++) cin>>a[i];
for(int i=0;i<=m;i++)
for(int j=i;j<=m;j++)
b[i] = (1ll*b[i] + 1ll*S[j][i]*a[j]%p)%p;
int ans = 0;
for(int i=0;i<=m;i++)
ans = (1ll*ans + 1ll*b[i]*fact[i]%p*xpow[i]%p*x1pow[i]%p)%p;
cout<<ans<<'\n';
return 0;
}

浙公网安备 33010602011771号