1. 程式人生 > 其它 >洛谷 P6667 - [清華集訓2016] 如何優雅地求和(下降冪多項式,多項式)

洛谷 P6667 - [清華集訓2016] 如何優雅地求和(下降冪多項式,多項式)

題面傳送門

wjz:《如何優雅地 AK NOI》

我:如何優雅地爆零

首先,按照這題總結出來的一個小套路,看到多項式與組合數結合的題,可以考慮將普通多項式轉為下降冪多項式,因為下降冪和組合數都可以用階乘相除的形式表示,而對於兩個組合數相乘我們有恆等式 \(\dbinom{n}{m}\dbinom{m}{k}=\dbinom{n}{k}\dbinom{n-k}{m-k}\),這樣我們可以將原式中待列舉變數 \(m\) 從兩個組合數中轉移到一個組合數(\(\dbinom{n-k}{m-k}\))中,也就進而可以用二項式定理等公式化簡了。

因此此題我們也可以考慮設 \(f(x)=\sum\limits_{i=0}^mb_ix^{\underline{i}}\)

,下面開始推式子:

\[\begin{aligned} ans&=\sum\limits_{k=0}^mf(k)\dbinom{n}{k}x^k(1-x)^{n-k}\\ &=\sum\limits_{k=0}^n\sum\limits_{j=0}^mb_jk^{\underline{j}}\dbinom{n}{k}x^k(1-x)^{n-k}\\ &=\sum\limits_{j=0}^mb_jj!\sum\limits_{k=j}^n\dbinom{k}{j}\dbinom{n}{k}x^k(1-x)^{n-k}\\ &=\sum\limits_{j=0}^mb_jj!\dbinom{n}{j}\sum\limits_{k=j}^n\dbinom{n-j}{k-j}x^k(1-x)^{n-k}\\ &=\sum\limits_{j=0}^mb_jj!\dbinom{n}{j}\sum\limits_{k=0}^{n-j}\dbinom{n-j}{k}x^{k+j}(1-x)^{n-k-j}\\ &=\sum\limits_{j=0}^mb_jj!\dbinom{n}{j}x^j(1-x+x)^{n-j}\\ &=\sum\limits_{j=0}^mb_jj!\dbinom{n}{j}x^j \end{aligned} \]

因此我們只需求出 \(b_j\)

即可線上性的時間內計算出 \(ans\)

接下來我們的任務是怎樣由 \(f(x)\) 的點值計算出 \(b_i\),考慮 \(f(x)\)\(\text{EGF}\),那麼有

\[\begin{aligned} \sum\limits_{n}\dfrac{f(n)x^n}{n!}&=\sum\limits_{n}\sum\limits_{j=0}^mb_jn^{\underline{j}}\dfrac{x^n}{n!}\\ &=\sum\limits_{j=0}^mb_j\sum\limits_{n}\dfrac{x^n}{(n-j)!}\\ &=\sum\limits_{j=0}^mb_jx^j\sum\limits_{n}\dfrac{x^{n-j}}{(n-j)!} \end{aligned} \]

\(A=\sum\limits_{j=0}^mb_jx^j,B=\sum\limits_{j}\dfrac{x^j}{j!}=e^x\)

,那麼 \(\sum\limits_{n}\dfrac{f(n)x^n}{n!}=A\times B\)

\(A=(\sum\limits_{n}\dfrac{f(n)x^n}{n!})\times e^{-x}\),NTT 一下即可。

時間複雜度 \(n\log n\)

const int pr=3;
const int MOD=998244353;
const int ipr=(MOD+1)/3;
const int MAXP=1<<16;
int qpow(int x,int e){
	int ret=1;
	for(;e;e>>=1,x=1ll*x*x%MOD) if(e&1) ret=1ll*ret*x%MOD;
	return ret;
}
int rev[MAXP+5];
void NTT(vector<int> &a,int len,int type){
	int lg=31-__builtin_clz(len);
	for(int i=0;i<len;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<lg-1);
	for(int i=0;i<len;i++) if((i-rev[i])>>31) swap(a[i],a[rev[i]]);
	for(int i=2;i<=len;i<<=1){
		int W=qpow((type<0)?ipr:pr,(MOD-1)/i);
		for(int j=0;j<len;j+=i){
			for(int k=0,w=1;k<(i>>1);k++,w=1ll*w*W%MOD){
				int X=a[j+k],Y=1ll*w*a[(i>>1)+j+k]%MOD;
				a[j+k]=(X+Y)%MOD;a[(i>>1)+j+k]=(X-Y+MOD)%MOD;
			}
		}
	} if(!~type) for(int j=0,ivn=qpow(len,MOD-2);j<len;j++) a[j]=1ll*a[j]*ivn%MOD;
}
vector<int> conv(vector<int> a,vector<int> b){
	int LEN=1;while(LEN<a.size()+b.size()) LEN<<=1;a.resize(LEN,0);b.resize(LEN,0);
	NTT(a,LEN,1);NTT(b,LEN,1);for(int i=0;i<LEN;i++) a[i]=1ll*a[i]*b[i]%MOD;
	NTT(a,LEN,-1);return a;
}
int n,m,x,fac[MAXP+5],ifac[MAXP+5];
void init_fac(int n){
	for(int i=(fac[0]=ifac[0]=ifac[1]=1)+1;i<=n;i++) ifac[i]=1ll*ifac[MOD%i]*(MOD-MOD/i)%MOD;
	for(int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%MOD,ifac[i]=1ll*ifac[i]*ifac[i-1]%MOD;
}
int main(){
	scanf("%d%d%d",&n,&m,&x);vector<int> a(m+1),b(m+1);init_fac(m);
	for(int i=0;i<=m;i++) scanf("%d",&a[i]),a[i]=1ll*a[i]*ifac[i]%MOD;
	for(int i=0;i<=m;i++) b[i]=((~i&1)?ifac[i]:(MOD-ifac[i]));a=conv(a,b);
	int ans=0,cur=1;for(int i=0;i<=m;i++) ans=(ans+1ll*a[i]*cur%MOD*qpow(x,i))%MOD,cur=1ll*cur*(n-i)%MOD;
	printf("%d\n",ans);
	return 0;
}