题解 [联合省选 2020 A] 组合数问题(LOJ #3300 / 洛谷 P6620)【第二类斯特林数 下降幂多项式】

题目链接:洛谷 P6620 / LOJ #3300

题意

求: ∑ k = 0 n f ( k ) × x k × ( n k )   m o d   p \sum_{k=0}^n f(k)\times x^k\times{n\choose k}\bmod p k=0nf(k)×xk×(kn)modp,其中 f f f 为一个 m m m 次多项式, n , x n,x n,x 给定, p p p 为给定的数(不一定是质数)。 n , x , p ≤ 1 0 9 n,x,p\leq 10^9 n,x,p109 m ≤ 1 0 3 m\leq 10^3 m103

题解

多项式与组合数不太搭,我们假装已经把它转化成了下降幂多项式 f ( x ) = ∑ i = 0 m b i x i ‾ f(x)=\sum_{i=0}^mb_ix^{\underline i} f(x)=i=0mbixi

然后各种推式子:

( n k ) k m ‾ = n ! k ! ( n − k ) ! k ! ( k − m ) ! = n ! ( n − k ) ! ( k − m ) ! = ( n − m ) ! ( n − k ) ! ( k − m ) ! n ! ( n − m ! ) = ( n − m k − m ) n m ‾ \begin{aligned}{n\choose k}k^{\underline m}=&{n!\over k!(n-k)!}{k!\over (k-m)!}\\ =&{n!\over (n-k)!(k-m)!}\\ =&{(n-m)!\over (n-k)!(k-m)!}{n!\over (n-m!)}\\ =&{n-m\choose k-m}n^{\underline m}\end{aligned} (kn)km====k!(nk)!n!(km)!k!(nk)!(km)!n!(nk)!(km)!(nm)!(nm!)n!(kmnm)nm

∑ k = 0 n f ( k ) × x k × ( n k ) = ∑ k = 0 n ∑ i = 0 m b i k i ‾ × x k × ( n k ) = ∑ k = 0 n ∑ i = 0 m b i × ( n − i k − i ) n i ‾ × x k = ∑ i = 0 m b i n i ‾ ∑ k = 0 n ( n − i k − i ) x k \begin{aligned}&\sum_{k=0}^n f(k)\times x^k\times{n\choose k}\\ =&\sum_{k=0}^n \sum_{i=0}^mb_ik^{\underline i}\times x^k\times{n\choose k}\\ =&\sum_{k=0}^n\sum_{i=0}^mb_i\times {n-i\choose k-i}n^{\underline i}\times x^k\\ =&\sum_{i=0}^mb_in^{\underline i}\sum_{k=0}^n{n-i\choose k-i}x^k\end{aligned} ===k=0nf(k)×xk×(kn)k=0ni=0mbiki×xk×(kn)k=0ni=0mbi×(kini)ni×xki=0mbinik=0n(kini)xk

( n − i k − i ) n-i\choose k-i (kini) k < i kk<i 时为 0,所以内层求和号改为枚举 k − i k-i ki

∑ i = 0 m b i n i ‾ ∑ k = 0 n ( n − i k − i ) x k = ∑ i = 0 m b i n i ‾ x i ∑ k = 0 n − i ( n − i k ) x k = ∑ i = 0 m b i n i ‾ x i ( x + 1 ) n − i \begin{aligned}&\sum_{i=0}^mb_in^{\underline i}\sum_{k=0}^n{n-i\choose k-i}x^k\\ =&\sum_{i=0}^mb_in^{\underline i}x^i\sum_{k=0}^{n-i}{n-i\choose k}x^k\\ =&\sum_{i=0}^mb_in^{\underline i}x^i(x+1)^{n-i}\end{aligned} ==i=0mbinik=0n(kini)xki=0mbinixik=0ni(kni)xki=0mbinixi(x+1)ni

这个可以 O ( m ) O(m) O(m)(当然我懒每次都用快速幂是 O ( m log ⁡ n ) O(m\log n) O(mlogn) 的)计算。

考虑如何转普通多项式为下降幂多项式:

x k = ∑ i = 0 k x i ‾ S ( k , i ) x^k=\sum\limits_{i=0}^kx^{\underline i}S(k,i) xk=i=0kxiS(k,i)

因此下降幂多项式的每一项系数都是普通多项式次数比它高的项的系数各自乘一个斯特林数之和, O ( m 2 ) O(m^2) O(m2) 求一下斯特林数,再 O ( m 2 ) O(m^2) O(m2) 模拟一下即可。

代码:

/**********
Author: WLBKR5
Problem: loj 3300, luogu 6620
Name: 组合数问题 
Source: 联合省选 2020 A卷 
Algorithm: 第二类斯特林数, 下降幂多项式 
Date: 2020/06/24
Statue: accepted
Submission: loj.ac/submission/844626, www.luogu.com.cn/record/34624085
**********/
#include
using namespace std; 
int getint(){
	int ans=0,f=1;
	int c=getchar();
	while(c<'0'||c>'9'){
		if(c=='-')f=-1;
		c=getchar();
	} 
	while(c>='0'&&c<='9'){
		ans=ans*10+c-'0';
		c=getchar();
	}
	return ans*f;
} 
const int M=1010;
int mod;
int f[M],g[M];
int s[M][M];
int qpow(int x,int y){
	int ans=1;
	while(y){
		if(y&1)ans=ans*1ll*x%mod;
		x=x*1ll*x%mod;
		y>>=1;
	}
	return ans;
}

int main(){
	int n=getint(),x=getint();mod=getint();int m=getint();
	for(int i=0;i<=m;i++)f[i]=getint();
	for(int i=0;i<=m;i++)s[i][0]=s[0][i]=!i;
	for(int i=1;i<=m;i++)
		for(int j=1;j<=i;j++)
			s[i][j]=(s[i-1][j]*1ll*j+s[i-1][j-1])%mod;
	for(int i=0;i<=m;i++){
		for(int j=i;j<=m;j++){
			g[i]=(g[i]+f[j]*1ll*s[j][i])%mod;
		}
	}
	int ans=0,tmp=1;
	for(int i=0;i<=m;i++){
		ans=(ans+g[i]*1ll*tmp%mod*qpow(x,i)%mod*qpow(x+1,n-i))%mod;
		tmp=tmp*1ll*(n-i)%mod;
	}
	cout<<ans;
	return 0;
}

(跑得挺快)

你可能感兴趣的:(题解,#,来源-各省省选,#)