【LOJ6569】仙人掌计数(生成函数)(多项式全家桶)(牛顿迭代)

传送门

  • 题意: n n n 个点带标号的仙人掌个数
  • 求一个有根的个数,令其 E G F EGF EGF f ( x ) f(x) f(x),那么一个根可以在多个环,或是只连出去一条边,对于环上的点,是以这个点为根的有序拼接(这样就不用管环上的顺序了),但是直接无序拼接的话正反会被算一遍,然后我们将每个环的贡献 exp ⁡ \exp exp 起来可以得到
    f ( x ) = x exp ⁡ ( f ( x ) + ∑ i ≥ 2 f i ( x ) 2 ) = x exp ⁡ ( 2 f ( x ) − f 2 ( x ) 2 − 2 f ( x ) ) f(x)=x\exp (f(x)+\sum_{i\ge 2}\frac{f^i(x)}{2})=x\exp (\frac{2f(x)-f^2(x)}{2-2f(x)}) f(x)=xexp(f(x)+i22fi(x))=xexp(22f(x)2f(x)f2(x))
    解方程,牛顿迭代,假设求得 f 0 f_0 f0 使得 H ( f 0 ) ≡ 0 ( m o d   x n ) H(f_0)\equiv 0(mod\ x^{n}) H(f0)0(mod xn)
    H ( f ) ≡ H ( f 0 ) + H ′ ( f 0 ) ( f − f 0 ) ( m o d x 2 n ) H(f)\equiv H(f_0)+H'(f_0)(f-f_0)(mod x^{2n}) H(f)H(f0)+H(f0)(ff0)(modx2n),即 f = f 0 − H ( f 0 ) H ′ ( f 0 ) f=f_0-\frac{H(f_0)}{H'(f_0)} f=f0H(f0)H(f0)
    H ′ ( f ) = ( 2 f − f 2 2 − 2 f ) ′ x exp ⁡ ( 2 f − f 2 2 − 2 f ) − 1 ( 2 f − f 2 2 − 2 f ) ′ = ( 2 − 2 f ) ( 2 − 2 f ) + 2 ( 2 f − f 2 ) ( 2 − 2 f ) 2 = 1 + 4 f − 2 f 2 ( 2 − 2 f ) 2 H'(f)=(\frac{2f-f^2}{2-2f})'x\exp(\frac{2f-f^2}{2-2f})-1\\ (\frac{2f-f^2}{2-2f})'=\frac{(2-2f)(2-2f)+2(2f-f^2)}{(2-2f)^2}=1+\frac{4f-2f^2}{(2-2f)^2} H(f)=(22f2ff2)xexp(22f2ff2)1(22f2ff2)=(22f)2(22f)(22f)+2(2ff2)=1+(22f)24f2f2
    然后就可以迭代了,实现得不是很精细所以应该有点慢
#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; }
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; }
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); }
cs int M = 1 << 20 | 5, C = 20;
cs int N = 131200;
int fac[M], ifac[M], iv[M];
void output(poly a){
	for(int i=0; i<a.size(); i++) cout<<a[i]<<" ";
	puts("");
}
void pre_work(int n){
	fac[0]=fac[1]=ifac[0]=ifac[1]=iv[0]=iv[1]=1;
	for(int i=2; i<=n; i++) iv[i]=mul(Mod-Mod/i,iv[Mod%i]);
	for(int i=2; i<=n; i++) fac[i]=mul(fac[i-1],i);
	for(int i=2; i<=n; i++) ifac[i]=mul(ifac[i-1],iv[i]);
}
poly w[C+1];
void NTT_init(){
	for(int i=1; i<=C; i++) w[i].resize(1<<(i-1));
	int wn=ksm(3,(Mod-1)/(1<<C)); w[C][0]=1;
	for(int i=1; i<(1<<(C-1)); i++) w[C][i]=mul(w[C][i-1],wn);
	for(int i=C-1;i;i--) for(int j=0; j<(1<<(i-1)); j++) w[i][j]=w[i+1][j<<1];
}
int up, bit; poly rev;
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; 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=4; (lim>>2)<deg; lim<<=1){
		c.resize(lim>>1); init(lim);
		for(int i=0; i<(lim>>1); i++) c[i]=i<(int)a.size()?a[i]:0;
		c.resize(up); b.resize(up); NTT(b); NTT(c);
		for(int i=0; i<up; i++) Mul(b[i],dec(2,mul(b[i],c[i])));
		NTT(b,-1); b.resize(lim>>1); 
	} b.resize(deg); return b;
}
poly deriv(poly a){
	for(int i=0; i+1<(int)a.size(); i++) a[i]=mul(i+1,a[i+1]);
	a.pop_back(); return a;
}
poly integ(poly a){
	a.pb(0);
	for(int i=a.size()-1;i;i--) a[i]=mul(iv[i],a[i-1]);
	a[0]=0; 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<(int)a.size()?a[i]:0,c[i]);
		b=b*c; b.resize(lim); 
	} b.resize(deg); return b;
}
poly operator * (int coe, poly a){
	for(int i=0; i<(int)a.size(); i++)
	Mul(a[i],coe); return a;
}
poly operator + (poly a, poly b){
	int deg = max(a.size(),b.size()); a.resize(deg); b.resize(deg);
	for(int i=0; i<deg; i++) Add(a[i],b[i]); return a;
}
poly operator - (poly a, poly b){
	int deg = max(a.size(),b.size()); a.resize(deg); b.resize(deg);
	for(int i=0; i<deg; i++) Dec(a[i],b[i]); return a;
}
poly Mulx(poly a){ a.insert(a.begin(),0); return a; }
poly Newton(int n){
	if(n==1) return poly(1,1);
	poly f0 = Newton((n+1)>>1);
	poly t = Mulx(Exp((2*f0-f0*f0)*inv(poly(1,2)-2*f0,n),n));t.resize(n);
	poly f = f0 - ((2*t-2*f0)*inv((poly(1,1)+inv((f0-poly(1,1))*(f0-poly(1,1)),n))*t-poly(1,2),n)); 	
	f.resize(n); return f;
}
int main(){
	pre_work(1<<C); NTT_init();
	poly f = Newton(N); 
	int T, n; scanf("%d",&T);
	while(T--){
		scanf("%d",&n); 
		cout << mul(f[n],fac[n-1]) << '\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、付费专栏及课程。

余额充值