1. 程式人生 > 實用技巧 >Luogu P6620 [省選聯考 2020 A 卷] 組合數問題

Luogu P6620 [省選聯考 2020 A 卷] 組合數問題

都說和UOJ #269. 【清華集訓2016】如何優雅地求和很像,但是做過那題的我還是想不到轉成下降冪,真是白學了啊

假設我們現在把多項式\(f(k)=\sum_{i=0}^ m a_ik^i\)轉化為\(f(k)=\sum_{i=0}^m b_ik^{\underline{i}}\),運用下降冪與組合數相乘的漂亮性質:

\[C_n^k\times k^{\underline{m}}=C_{n-m}^{k-m}\times n^{\underline{m}} \]

證明很簡單,兩邊全部拆開乘一乘就發現是相等的,因此我們推一下式子:

\[\sum_{k=0}^n f(k)\times x^k\times C_n^k\\ =\sum_{i=0}^mb_i n^{\underline{i}}\sum_{k=0}^n C_{n-i}^{k-i} x^k\\ =\sum_{i=0}^mb_i n^{\underline{i}}\sum_{k=0}^{n-i} C_{n-i}^{k} x^{k+i}\\ =\sum_{i=0}^mb_i n^{\underline{i}}x^i\sum_{k=0}^{n-i} C_{n-i}^{k} x^{k}\\ =\sum_{i=0}^mb_i n^{\underline{i}}x^i(x+1)^{n-i} \]

考慮如何快速把一個多項式轉成下降冪形式,套用經典的第二類斯特林數性質:

\[x^n=\sum_{i=0}^n \left\{^n_i\right\} x^{\underline{i}} \]

帶入得:

\[f(k)=\sum_{i=0}^ m a_ik^i=\sum_{i=0}^ m a_i \sum_{j=0}^i \left\{^i_j\right\} k^{\underline{j}}\\ =\sum_{i=0}^m k^{\underline{i}}\sum_{j=i}^m \left\{^j_i\right\} a_j \]

因此\(b_i=\sum_{j=i}^m \left\{^j_i\right\} a_j\)

,直接\(O(m^2)\)預處理便可直接\(O(m)\)計算答案

#include<cstdio>
#define RI register int
#define CI const int&
using namespace std;
const int N=1005;
int n,x,mod,m,a[N],b[N],s[N][N],ans;
inline int quick_pow(int x,int p=mod-2,int mul=1)
{
	for (;p;p>>=1,x=1LL*x*x%mod) if (p&1) mul=1LL*mul*x%mod; return mul;
}
int main()
{
	RI i,j; for (scanf("%d%d%d%d",&n,&x,&mod,&m),i=0;i<=m;++i)
	scanf("%d",&a[i]); for (s[0][0]=s[1][1]=1,i=2;i<=m;++i) for (j=1;j<=i;++j)
	s[i][j]=(s[i-1][j-1]+1LL*s[i-1][j]*j%mod)%mod;
	for (i=0;i<=m;++i) for (j=i;j<=m;++j) (b[i]+=1LL*s[j][i]*a[j]%mod)%=mod;
	int cur=1; for (i=0;i<=m;++i)
	(ans+=1LL*b[i]*cur%mod*quick_pow(x,i)%mod*quick_pow(x+1,n-i)%mod)%=mod,cur=1LL*cur*(n-i)%mod;
	return printf("%d",ans),0;
}