[被踩计划] 题解 [省选联考 2020 A 卷] 组合数问题

为什么叫被踩记录呢?因为感觉自己之前真的是太菜了,打算把之前联赛等考过的题目做一做,看看自已以前有多菜,所以取名叫被踩记录。

题目链接

题目分析

首先要知道这些东西:

[n^m=sum_{i=0}^{n}{nchoose i}{mrace i}i! ]

[sum_{i=0}^{n}{nchoose i}x^i=(x+1)^n ]

[{nchoose m}{mchoose k}={nchoose k}{n-kchoose m-k} ]

然后就可以愉快地推式子了:

[sum_{k=0}^nsum_{i=0}^ma_ik^ix^k{nchoose k}= ]

[sum_{k=0}^nsum_{i=0}^ma_isum_{t=0}^i{kchoose t}{irace t}t!x^k{nchoose k}= ]

[sum_{i=0}^ma_isum_{t=0}^i{irace t}t!sum_{k=0}^n{kchoose t}{nchoose k}x^k= ]

[sum_{i=0}^ma_isum_{t=0}^i{irace t}t!sum_{k=0}^n{nchoose t}{n-tchoose k-t}x^k= ]

[sum_{i=0}^ma_isum_{t=0}^i{nchoose t}{irace t}t!x^tsum_{k=0}^{n-t}{n-tchoose k}x^k= ]

[sum_{i=0}^ma_isum_{t=0}^i{nchoose t}{irace t}t!x^t(x+1)^{n-t} ]

预处理 ({nchoose t},{irace t},t!,x^t,(x+1)^{n-t}) ,时间复杂度最多是 (mathcal O(m^2log_2n)) 的,然后再 (mathcal O(m^2)) 算答案就行了!

参考代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ch() getchar()
#define pc(x) putchar(x)
using namespace std;
template<typename T>void read(T&x){
	static char c;static int f;
	for(c=ch(),f=1;c<'0'||c>'9';c=ch())if(c=='-')f=-f;
	for(x=0;c>='0'&&c<='9';c=ch())x=x*10+(c&15);x*=f;
}
template<typename T>void write(T x){
	static char q[65];int cnt=0;
	if(x<0)pc('-'),x=-x;
	q[++cnt]=x%10,x/=10;
	while(x)
		q[++cnt]=x%10,x/=10;
	while(cnt)pc(q[cnt--]+'0');
}
const int maxm=1005;
int C[maxm],p,S[maxm][maxm],st[maxm],_t[maxm],_x[maxm],_x1[maxm];
int mo(const int x){
	return x>=p?x-p:x;
}
int _1;
int power(int a,int x){
	int re=_1;
	while(x){
		if(x&1)re=1ll*re*a%p;
		a=1ll*a*a%p,x>>=1;
	}
	return re;
}
int gcd(int x,int y){
	while(y){
		int t=x%y;
		x=y;
		y=t;
	}
	return x;
}
int main(){
	int n,x,m;
	read(n),read(x),read(p),read(m);
	_1=1%p;S[0][0]=C[0]=_t[0]=_x[0]=_1;
	for(int i=1;i<=m;++i){
		_t[i]=1ll*_t[i-1]*i%p;
		_x[i]=1ll*_x[i-1]*x%p;
		st[i]=n-i+1;int cp=i;
		for(int j=1;j<=i&&cp>1;++j){
			int t=gcd(st[j],cp);
			cp/=t,st[j]/=t;
		}
		C[i]=C[0];
		for(int j=1;j<=i;++j)
			C[i]=1ll*C[i]*st[j]%p,
			S[i][j]=mo(S[i-1][j-1]+1ll*S[i-1][j]*j%p);
	}
	_x1[m]=power((x+1)%p,n-m);
	for(int i=m-1;i>=0;--i)
		_x1[i]=1ll*_x1[i+1]*(x+1)%p;
	int ans=0;
	for(int i=0;i<=m;++i){
		int a,te=0;read(a);
		for(int t=0;t<=i;++t){
			te=mo(te+1ll*C[t]*S[i][t]%p*_t[t]%p*_x[t]%p*_x1[t]%p);
		}
		ans=mo(ans+1ll*te*a%p);
	}
	write(ans),pc('
');
	return 0;
}

原文地址:https://www.cnblogs.com/lsq147/p/13746426.html