[第一类斯特林求行]

[第一类斯特林求行]


如题,复杂度一个log

  • 代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353,g=3;
inline int add(int a,int b){a+=b;return a>=mod?a-mod:a;}
inline int sub(int a,int b){a-=b;return a<0?a+mod:a;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline int qpow(int a,int b){int ret=1;for(;b;b>>=1,a=mul(a,a))if(b&1)ret=mul(ret,a);return ret;}
const int N=5e5+5;
int rev[N],fac[N],ifac[N];

inline void init(int n){
	fac[0]=ifac[0]=1;for(int i=1;i<=n;i++)fac[i]=mul(fac[i-1],i);
	ifac[n]=qpow(fac[n],mod-2);for(int i=n-1;i;i--)ifac[i]=mul(ifac[i+1],i+1);
}
int comb(int a,int b){if(b>a)return 0;return mul(fac[a],mul(ifac[b],ifac[a-b]));}
/*math&comb*/
typedef vector<int> Poly;
void DFT(int *t,int n,int type){
	int l=0;while(1<<l<n)++l;
	for(int i=0;i<n;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
	for(int i=0;i<n;i++)if(rev[i]>i)swap(t[rev[i]],t[i]);
	for(int step=1;step<n;step<<=1){
		int wn=qpow(g,(mod-1)/(step<<1));
		for(int i=0;i<n;i+=step<<1){
			int w=1;
			for(int k=0;k<step;k++,w=mul(w,wn)){
				int x=t[i+k],y=mul(t[i+k+step],w);
				t[i+k]=add(x,y),t[i+k+step]=sub(x,y);
			}
		}
	}
	if(type==1)return;
	for(int i=1;i<n-i;i++)swap(t[i],t[n-i]);
	int inv=qpow(n,mod-2);
	for(int i=0;i<n;i++)t[i]=mul(t[i],inv);
}
Poly NTT(Poly A,int n,Poly B,int m){
	static Poly res,PolA,PolB;
	PolA=A,PolB=B;
	int len=1;while(len < n+m)len<<=1;
	res.resize(len);
	PolA.resize(len),PolB.resize(len);
	DFT(&PolA[0],len,1);DFT(&PolB[0],len,1);
	for(int i=0;i<len;i++) res[i]= mul(PolA[i],PolB[i]);
	DFT(&res[0],len,-1);
	res.resize(n+m-1);
	return res;
}
Poly NTT(Poly A,Poly B){
	return NTT(A,A.size(),B,B.size());
}

Poly Getstirling(int X){
	Poly ret;
	if(X==0){
		ret.resize(1);ret[0]=1;
		return ret;
	}
	if(X==1){
		ret.resize(2);ret[0]=0,ret[1]=1;
		return ret;
	}
	if(X==2){
		ret.resize(3);ret[0]=0,ret[1]=1,ret[2]=1;
	}
	int nn=X/2+1;
	Poly pst=Getstirling(X/2);
	int t=X/2;
	Poly snd=pst,tmp;
	for(int i=0;i<nn;i++) snd[i]=mul(snd[i],fac[i]);
	tmp.resize(nn);
	for(int i=0;i<nn;i++) tmp[i]=mul(qpow(t,nn-1-i),ifac[nn-1-i]);
	Poly R=NTT(snd,tmp);
	snd.resize(nn);
	for(int i=0;i<nn;i++) snd[i]=mul(ifac[i],R[i+nn-1]);
	ret=NTT(pst,snd);
	if(X%2){
		ret.resize(X+1);
		for(int i=X;i;i--){
			ret[i]=add(mul(ret[i],X-1),ret[i-1]);
		}
	}
	return ret;
}
int n,a,b;
Poly S;


int main()
{
	cin>>n>>a>>b;a--,b--;
	if(a<0||b<0){
		puts("0");return 0;
	}
	init(400000);S=Getstirling(n-1);
	int St=0;
	if(a+b<S.size()){
		St=S[a+b];
	}
	St=mul(St,comb(a+b,b));
	printf("%d\n",St);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值