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

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

题目链接

题目分析

首先要知道这些东西:

\[n^m=\sum_{i=0}^{n}{n\choose i}{m\brace i}i! \]

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

\[{n\choose m}{m\choose k}={n\choose k}{n-k\choose m-k} \]

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

\[\sum_{k=0}^n\sum_{i=0}^ma_ik^ix^k{n\choose k}= \]

\[\sum_{k=0}^n\sum_{i=0}^ma_i\sum_{t=0}^i{k\choose t}{i\brace t}t!x^k{n\choose k}= \]

\[\sum_{i=0}^ma_i\sum_{t=0}^i{i\brace t}t!\sum_{k=0}^n{k\choose t}{n\choose k}x^k= \]

\[\sum_{i=0}^ma_i\sum_{t=0}^i{i\brace t}t!\sum_{k=0}^n{n\choose t}{n-t\choose k-t}x^k= \]

\[\sum_{i=0}^ma_i\sum_{t=0}^i{n\choose t}{i\brace t}t!x^t\sum_{k=0}^{n-t}{n-t\choose k}x^k= \]

\[\sum_{i=0}^ma_i\sum_{t=0}^i{n\choose t}{i\brace t}t!x^t(x+1)^{n-t} \]

预处理 \({n\choose t},{i\brace t},t!,x^t,(x+1)^{n-t}\) ,时间复杂度最多是 \(\mathcal O(m^2\log_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('\n');
	return 0;
}

上一篇:关于 NOI2019 斗主地 的证明


下一篇:组合数学学习笔记2