#范德蒙德卷积,第二类斯特林数,NTT#洛谷 2791 幼儿园篮球题

题目

\(T(T\leq 200)\)组数据求

\[\frac{1}{C(n,k)}\sum_{i=0}^kC(m,i)C(n-m,k-i)i^L \]

对于所有数据满足 \(n,m,k\leq 2*10^7,L\leq 2*10^5\)


分析

主要是这个 \(L\) 次方的问题,考虑用第二类斯特林数转化一下,就是

\[=\frac{1}{C(n,k)}\sum_{i=0}^kC(m,i)C(n-m,k-i)\sum_{j=0}^L Stir(L,j)*j!*C(i,j) \]

提到前面去就是

\[=\frac{1}{C(n,k)}\sum_{j=0}^L Stir(L,j)*j!\sum_{i=0}^k C(m,i)C(n-m,k-i)C(i,j) \]

考虑 \(C(m,i)C(i,j)=C(m,j)C(m-j,i-j)\),那么

\[=\frac{1}{C(n,k)}\sum_{j=0}^L Stir(L,j)*j!C(m,j)\sum_{i=0}^k C(m-j,i-j)C(n-m,k-i) \]

利用范德蒙德卷积可以得到

\[=\frac{1}{C(n,k)}\sum_{j=0}^L Stir(L,j)*j!C(m,j)C(n-j,k-j) \]

用NTT维护一行的第二类斯特林数即可


代码

#include <cstdio>
#include <cctype>
#include <cmath>
#include <cstring>
#include <algorithm>
#define mem(f,n) memset(f,0,sizeof(int)*(n))
#define cpy(f,g,n) memcpy(f,g,sizeof(int)*(n))
using namespace std;
const int mod=998244353,N=400011,inv3=332748118;
typedef long long lll; typedef unsigned long long ull;
int n,m,Gmi[31],Imi[31],T,L,len,ff[N<<2],gg[N<<2],tt[N<<2],inv[N*50],fac[N*50];
int iut(){
    int ans=0; char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    return ans;
}
void print(int ans){
    if (ans>9) print(ans/10);
    putchar(ans%10+48);
}
int ksm(int x,int y){
	int ans=1;
	for (;y;y>>=1,x=1ll*x*x%mod)
	    if (y&1) ans=1ll*ans*x%mod;
	return ans;
}
namespace Theoretic{
	int rev[N<<2],LAST; ull Wt[N<<2],F[N<<2];
	void Pro(int n){
		if (LAST==n) return; LAST=n,Wt[0]=1;
		for (int i=0;i<n;++i)
		    rev[i]=(rev[i>>1]>>1)|((i&1)?n>>1:0);
	}
	void NTT(int *f,int n,int op){
		Pro(n);
		for (int i=0;i<n;++i) F[i]=f[rev[i]];
	    for (int o=1,len=1;len<n;++o,len<<=1){
	    	int W=(op==1)?Gmi[o]:Imi[o];
	    	for (int j=1;j<len;++j) Wt[j]=Wt[j-1]*W%mod;
	    	for (int i=0;i<n;i+=len+len)
	    	for (int j=0;j<len;++j){
	    		int t=Wt[j]*F[i|j|len]%mod;
	    		F[i|j|len]=F[i|j]+mod-t,F[i|j]+=t;
			}
	    	if (o==10) for (int j=0;j<n;++j) F[j]%=mod;
		}
		if (op==-1){
			int invn=ksm(n,mod-2);
			for (int i=0;i<n;++i) F[i]=F[i]%mod*invn%mod;
		}else for (int i=0;i<n;++i) F[i]%=mod;
		for (int i=0;i<n;++i) f[i]=F[i];
    }
	void Cb(int *f,int *g,int n){
		for (int i=0;i<n;++i) f[i]=1ll*f[i]*g[i]%mod;
	}
}
void GmiImi(){
	for (int i=0;i<31;++i) Gmi[i]=ksm(3,(mod-1)/(1<<i));
	for (int i=0;i<31;++i) Imi[i]=ksm(inv3,(mod-1)/(1<<i));		
}
int main(){
	n=iut(),m=iut(),T=iut(),L=iut(); if (n<L) n=L;
    inv[0]=inv[1]=fac[0]=fac[1]=1,GmiImi();
	for (int i=2;i<=n;++i) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
	for (int i=2;i<=n;++i) fac[i]=1ll*fac[i-1]*i%mod,inv[i]=1ll*inv[i-1]*inv[i]%mod;
	for (int i=0;i<=L;++i) ff[i]=1ll*((i&1)?mod-1:1)*inv[i]%mod,gg[i]=1ll*ksm(i,L)*inv[i]%mod;
    for (len=1;len<L+L+2;len<<=1); cpy(tt,gg,len);
    Theoretic::NTT(ff,len,1),Theoretic::NTT(tt,len,1),
	Theoretic::Cb(ff,tt,len),Theoretic::NTT(ff,len,-1);
	mem(ff+L+1,len-L-1),mem(tt,len);
	for (int j=1;j<=T;++j){
		int _n=iut(),_m=iut(),_k=iut(),ans=0,lim=min(_k,min(_m,L));
		for (int i=0;i<=lim;++i) ans=(ans+1ll*ff[i]*inv[_m-i]%mod*fac[_n-i]%mod*inv[_k-i])%mod;
		ans=1ll*ans*fac[_m]%mod*fac[_k]%mod*inv[_n]%mod;
		print(ans),putchar(10);
	}
    return 0;
}
posted @ 2021-11-16 16:14  lemondinosaur  阅读(42)  评论(0)    收藏  举报