【P5850】calc 加强版(生成函数)(多项式)

传送门

  • 题意:有 ( k n ) \binom{k}{n} (nk) 种情况,每种情况是选出来的数之积,求 n ∈ [ 1 , m ] n\in[1,m] n[1,m] 的每种情况的值
    那么就是求 ∏ ( 1 + i x ) \prod(1+ix) (1+ix) [ 1 , n ] [1,n] [1,n] 项系数,那么用 ln ⁡ , exp ⁡ \ln,\exp ln,exp 来转换,即
    exp ⁡ ( ∑ ln ⁡ ( 1 + i x ) ) \exp(\sum \ln(1+ix)) exp(ln(1+ix)),把 ln ⁡ \ln ln 泰勒展开,就是
    exp ⁡ ( ∑ i ∑ j ≥ 1 i j ( − 1 ) j + 1 j x j ) = exp ⁡ ( ∑ j ≥ 1 ( − 1 ) j + 1 j x j ( ∑ i i j ) ) \exp(\sum_i\sum_{j\ge 1}\frac{i^j(-1)^{j+1}}{j}x^j)=\exp(\sum_{j\ge 1}\frac{(-1)^{j+1}}{j}x^j(\sum_i i^j)) exp(ij1jij(1)j+1xj)=exp(j1j(1)j+1xj(iij))
    考虑快速对 j ∈ [ 1 , n ] j\in[1,n] j[1,n] ∑ i i j \sum_i i^j iij,这个拉格朗日插值可以 O ( n 2 ) O(n^2) O(n2)
    写出生成函数 F ( x ) = ∑ j ( ∑ i i j ) x j j ! F(x)=\sum_{j}(\sum_{i}i^j)\frac{x^j}{j!} F(x)=j(iij)j!xj,上回又道题是写成 o g f ogf ogf,但是凉了, e g f egf egf 有巧妙的性质:
    F ( x ) = ∑ i ∑ j i j x j j ! = ∑ i e i x = e ( k + 1 ) x − e x e x − 1 F(x)=\sum_{i}\sum_j\frac{i^jx^j}{j!}=\sum_ie^{ix}=\frac{e^{(k+1)x}-e^x}{e^x-1} F(x)=ijj!ijxj=ieix=ex1e(k+1)xex
    同时约一个 x x x 即可多项式求逆
#include<bits/stdc++.h>
#define cs const
#define pb push_back
#define poly vector<int>
using namespace std;
cs int Mod = 998244353;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b; }
int dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
int mul(int a, int b){ return 1ll * a * b % Mod; }
void Add(int &a, int b){ a = add(a,b); }
void Mul(int &a, int b){ a = mul(a,b); }
void Dec(int &a, int b){ a = dec(a,b); }
int ksm(int a, int b){ int as=1; for(;b;b>>=1,a=mul(a,a)) if(b&1) as=mul(as,a); return as; }
cs int N = 5e5 + 50;
int k, n, fc[N], ifc[N];
cs int K = 20;
int up, bit; poly rev;
poly w[K+1]; int iv[1<<K|5];
void OGF(poly a){ for(int c:a) cout<<c<<" ";puts(""); }
void EGF(poly a){ for(int i=0; i<a.size(); i++) cout<<mul(a[i],fc[i])<<" ";puts(""); }
void NTT_init(){
	for(int i=1; i<=K; i++) w[i].resize(1<<(i-1)); 
	int wn=ksm(3,(Mod-1)/(1<<K)); w[K][0]=1;
	for(int i=1; i<(1<<(K-1)); i++) w[K][i]=mul(w[K][i-1],wn);
	for(int i=K-1;i;i--) for(int j=0; j<(1<<(i-1)); j++) w[i][j]=w[i+1][j<<1];
	iv[0]=iv[1]=1; for(int i=2; i<=(1<<K); i++) iv[i]=mul(Mod-Mod/i,iv[Mod%i]);
}
void Fac_init(int n){
	fc[0]=fc[1]=ifc[0]=ifc[1]=1;
	for(int i=2; i<=n; i++) fc[i]=mul(fc[i-1],i);
	for(int i=2; i<=n; i++) ifc[i]=mul(ifc[i-1],iv[i]);
}
void init(int deg){
	up=1; bit=0; while(up<deg) up<<=1,++bit; rev.resize(up);
	for(int i=0; i<up; i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
}
void NTT(poly &a, int typ=1){
	for(int i=0; i<up; i++) if(i<rev[i]) swap(a[i],a[rev[i]]);
	for(int i=1,l=1; i<up; i<<=1,++l)
	for(int j=0; j<up; j+=(i<<1))
	for(int k=0; k<i; k++){
		int x=a[k+j], y=mul(w[l][k],a[k+j+i]);
		a[k+j]=add(x,y); a[k+j+i]=dec(x,y);
	}
	if(typ==-1){
		reverse(a.begin()+1,a.end());
		for(int i=0; i<up; i++) Mul(a[i],iv[up]);
	}
}
poly operator * (poly a, poly b){
	int deg=a.size()+b.size()-1; 
	if(a.size()<=16||b.size()<=16){
		poly c(deg,0); 
		for(int i=0; i<(int)a.size(); i++)
		for(int j=0; j<(int)b.size(); j++)
		Add(c[i+j],mul(a[i],b[j])); return c;
	}
	init(deg); a.resize(up); b.resize(up); NTT(a); NTT(b);
	for(int i=0; i<up; i++) Mul(a[i],b[i]); NTT(a,-1);
	a.resize(deg); return a;
}
poly inv(poly a, int deg){
	poly b(1,ksm(a[0],Mod-2)),c;
	for(int lim=2; (lim>>1)<deg; lim<<=1){
		c=a; c.resize(lim); init(lim<<1);
		c.resize(up); b.resize(up); NTT(c); NTT(b);
		for(int i=0; i<up; i++) Mul(b[i],dec(2,mul(b[i],c[i])));
		NTT(b,-1); b.resize(lim); 
	} b.resize(deg); return b;
}
poly integ(poly a){
	a.pb(0);
	for(int i=a.size()-1; i>=1; i--) a[i]=mul(a[i-1],iv[i]);
	a[0]=0; return a;
}
poly deriv(poly a){
	for(int i=0; i+1<(int)a.size(); i++) a[i]=mul(a[i+1],i+1);
	a.pop_back(); return a;
}
poly ln(poly a, int deg){
	a=integ(inv(a,deg)*deriv(a)); a.resize(deg);
	return a;
}
poly Exp(poly a, int deg){
	poly b(1,1), c;
	for(int lim=2; (lim>>1)<deg; lim<<=1){
		c=ln(b,lim); Dec(c[0],1);
		for(int i=0; i<lim; i++) c[i]=dec(i<a.size()?a[i]:0,c[i]);
		b=b*c; b.resize(lim);
	} b.resize(deg); return b;
}
int main(){
	#ifdef FSYolanda
	freopen("1.in","r",stdin);
	#endif
	scanf("%d%d",&k,&n); ++n; 
	NTT_init(); Fac_init(n); poly f,g;
	for(int i=0; i<n; i++) f.pb(ifc[i+1]);
	for(int i=0,coe=k+1; i<n; i++) g.pb(mul(ifc[i+1],dec(coe,1))),Mul(coe,k+1);
	f=g*inv(f,n); f[0]=0;
	for(int i=1; i<n; i++){
	if(i&1^1) f[i]=dec(0,f[i]);
	Mul(f[i],fc[i-1]);
	}  f=Exp(f,n);
	for(int i=1; i<n; i++) cout<<mul(fc[i],f[i])<<'\n';
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FSYo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值