[省选联考 2020 A 卷] 组合数问题 题解报告

题目要求

\[\sum_{k=0}^nf(k)\times x^k\times\dbinom{n}{k} \]

我觉得 ix35 的方法还是蛮不错的,其他的斯特林数推导和组合意义 dp 都给我看傻了

首先考虑将 \(f\) 拆成单项式有

\[\sum_{i=0}^ma_i\times k^i\times \dbinom{n}{k} \]

\(k\times \dbinom{n}{k}=n\times \dbinom{n-1}{k-1}\) 向外扩展

\(k^2\times \dbinom{n}{k},k^3\times\dbinom{n}{k}\dots\) 手算一遍

可以发现对于 \(k^p\times \dbinom{n}{k}\) 有一般形式

\[=\sum_{i=1}^pS(p,j)\times n^{\underline{j}}\times\dbinom{n-j}{k-j} \]

并且对于 \(S(p,j)=S(i-1,j)\times j+S(i-1,j-1)\) 存在这个递归式

这个时候回带到原式中

\[\sum_{k=0}^{n}x^k\left(a_0+\sum_{i=1}^ma_i\times k^i\times \dbinom{n}{k}\right) \]

务必要特殊讨论 \(a_0\) 的存在,否则你会因为这个死活过不去大样例。

把关于 n 的求和符号换进去,可以得到这样一个式子

\[\sum_{k=0}^nx^k\sum_{j=1}^i S(i,j)\times n^{\underline{j}}\times\dbinom{n-j}{k-j} \]

进一步交换

\[\sum_{j=1}^i S(i,j)\times n^{\underline{j}}\times\sum_{k=0}^nx^k\dbinom{n-j}{k-j} \]

单独考虑后面那个求和符号,等价于

\[x^j\sum_{k=0}^{n-j}x\dbinom{n-j}{k} \]

再用一步二项式定理(一定要带着那个 \(x^j\),不然还是只能过第一个样例

\[x^j\times(1+x)^{n-j} \]

整理一下

\[a_0(1+x)^n+\sum_{i=1}^ma_i\left(\sum_{j=1}^iS(i,j)\times n^{\underline{j}}\times x^j \times(1+x)^{n-j}\right) \]

然后这个一个依赖 \(n\) 的算法被我们改造成了依赖 \(m\) 的算法,复杂度是 \(O(m^2\log m)\)

#include<bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int,int>

template<typename _T>
inline void read(_T &x)
{
	x=0;char s=getchar();int f=1;
	while(s<'0'||s>'9') {f=1;if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}
	x*=f;
}

const int np = 1e3 + 5;

int a[np];
int x,n,m,p;
int s[np][np];
int dfac[np];
int x_[np];

inline int power(int a,int b)
{
	int res(1);
	while(b)
	{
		if(b & 1) res = res * a,res %= p;
		a = a * a ;
		a %= p;
		b >>= 1;
	}
	return res;
}

signed main()
{
	read(n),read(x),read(p),read(m);
	for(int i=0;i <=m;i++) read(a[i]);
	for(int i=1;i <= 1000;i ++)
	{
		s[i][1] = 1;
		for(int j=2;j <= i;j++)
		{
			s[i][j] = s[i-1][j]*j+s[i-1][j-1];
			s[i][j] %= p;
		}
		// for(int j=1;j<=i;j++) printf("%lld ",s[i][j]);
		// printf("\n");		
	}

	dfac[0] =1 ;
	for(int i=1;i <= 1000;i ++)
	{
		dfac[i] = dfac[i-1]*(n-i+1);
		dfac[i] %= p;
	}

	int Ans =power(1+x,n)*a[0];
	Ans %= p;
	for(int i=1;i <= m;i ++)
	{
		int qAns = 0;
		for(int j=1;j <= i;j ++)
		{
			qAns += ((((s[i][j] * dfac[j])%p) * power(x,j)%p) *power(1 + x,n-j))%p;
			qAns %= p;
		}
		qAns *= a[i];
		qAns %= p;
		Ans += qAns;
		Ans %= p;
		// printf("%lld\n",Ans);
	}

	// Ans  += ((n+1) * n* a[0])%p;
	// Ans %= p;
	printf("%lld",Ans);


}

以后遇到这样的数学推导题,经过一遍草率的推导得到了最终式子的时候,一定要从头认真推导一遍,每一个项都不能忽略

posted @ 2021-09-26 21:45  ·Iris  阅读(77)  评论(0编辑  收藏  举报