zoukankan      html  css  js  c++  java
  • LOJ6569 仙人掌计数 和 LG5434 荒漠计数

    仙人掌计数

    (n) 个点有标号仙人掌的个数。答案对 (998244353) 取模。

    (n leq 10^5)

    题解

    https://www.luogu.com.cn/blog/NaCly-Fish-blog/solution-p5434

    我们随便钦定一个点作为根,设仙人掌数量的EGF为 (F(x))。(虽然题目中要求是无根的,但是最后答案就差一个(frac1n)而已,乘上就好了)

    考虑一坨东西与根相邻,分两种情况讨论:

    • 如果根连出去了一个单点,那么它也是仙人掌,所以这一块的生成函数还是 (F(x))

    • 如果根连出去了一个环,且共有(i+1)个点,那么其生成函数为 (frac{F(x)^i}{2})

      除以 (2) 是因为每种环都被正反算了两次。

    由于边和环都可以随便排列,所以它们总的生成函数就是:

    [expleft(F(x)+frac12sum_{i=2}^infty F(x)^i ight) ]

    (exp) 中右边那一坨东西,可以用等比数列化简:

    [expleft(F(x)+frac{F(x)^2}{2-2F(x)} ight)=exp frac{2F(x)-F(x)^2}{2-2F(x)} ]

    (F(x)^infty mod x^n=0)

    由于上面的推导都是没有考虑根的,所以我们把根算上,就能得到一个函数方程:

    [F(x)=xexp frac{2F(x)-F(x)^2}{2-2F(x)} ]

    推到这一步,接下来就比较好想了,直接牛顿迭代。
    只要求出(G(F(x)))的零点,就得到我们要的(F(x))了。

    [G(F(x))=xexp frac{2F(x)-F(x)^2}{2-2F(x)}-F(x) ]

    根据牛顿迭代式((F_n(x)) 表示下一次迭代的结果):

    [F_n(x)=F(x)-frac{G(F(x))}{G'(F(x))}\ G'(F(x))=left(xexp frac{2F(x)-F(x)^2}{2-2F(x)}-F(x) ight)'\ =left(frac{2F(x)-F(x)^2}{2-2F(x)} ight)'xexp frac{2F(x)-F(x)^2}{2-2F(x)}-1\ =frac{F(x)^2-2F(x)+2}{2(F(x)-1)^2}xexp frac{2F(x)-F(x)^2}{2-2F(x)}-1\ F_n(x)=F(x)-frac{2xexpfrac{2F(x)-F(x)^2}{2-2F(x)}-2F(x)}{left(1+frac{1}{(F(x)-1)^2} ight)xexpfrac{2F(x)-F(x)^2}{2-2F(x)}-2} ]

    (F(x)) 求导的时候把 (x) 看成常数。

    别看这个式子有那么大一坨,它的分子和分母都含有 (xexp frac{2F(x)-F(x)^2}{2-2F(x)})。按照这个式子直接算即可,注意所有多项式运算都要模 (x^{n+1})

    由于算出来的 (F(x)) 是有根仙人掌的生成函数,要把它变成无根的情况,它的 (n) 次项都要乘 (frac{1}{n})

    时间复杂度 (O(n log n))

    CO int N=262144;
    int omg[2][N],rev[N];
    int fac[N],inv[N],ifac[N];
    
    void NTT(poly&a,int dir){
    	int lim=a.size(),len=log2(lim);
    	for(int i=0;i<lim;++i) rev[i]=rev[i>>1]>>1|(i&1)<<(len-1);
    	for(int i=0;i<lim;++i)if(i<rev[i]) swap(a[i],a[rev[i]]);
    	for(int i=1;i<lim;i<<=1)
    		for(int j=0;j<lim;j+=i<<1)for(int k=0;k<i;++k){
    			int t=mul(omg[dir][N/(i<<1)*k],a[j+i+k]);
    			a[j+i+k]=add(a[j+k],mod-t),a[j+k]=add(a[j+k],t);
    		}
    	if(dir==1){
    		int ilim=fpow(lim,mod-2);
    		for(int i=0;i<lim;++i) a[i]=mul(a[i],ilim);
    	}
    }
    poly operator~(poly a){
    	int n=a.size();
    	poly b(1,fpow(a[0],mod-2));
    	if(n==1) return b;
    	int lim=2;
    	for(;lim<n;lim<<=1){
    		poly c(a.begin(),a.begin()+lim);
    		c.resize(lim<<1),NTT(c,0);
    		b.resize(lim<<1),NTT(b,0);
    		for(int i=0;i<lim<<1;++i) b[i]=mul(2+mod-mul(c[i],b[i]),b[i]);
    		NTT(b,1),b.resize(lim);
    	}
    	a.resize(lim<<1),NTT(a,0);
    	b.resize(lim<<1),NTT(b,0);
    	for(int i=0;i<lim<<1;++i) b[i]=mul(2+mod-mul(a[i],b[i]),b[i]);
    	NTT(b,1),b.resize(n);
    	return b;
    }
    poly log(poly a){
    	int n=a.size();
    	poly b=~a;
    	a.resize(n-1);
    	for(int i=0;i<n-1;++i) a[i]=mul(a[i+1],i+1);
    	int lim=1<<(int)ceil(log2(2*n-2));
    	a.resize(lim),NTT(a,0);
    	b.resize(lim),NTT(b,0);
    	for(int i=0;i<lim;++i) a[i]=mul(a[i],b[i]);
    	NTT(a,1),a.resize(n);
    	for(int i=n-1;i>=1;--i) a[i]=mul(a[i-1],inv[i]);
    	return a[0]=0,a;
    }
    poly exp(poly a){
    	int n=a.size();
    	poly b(1,1); // a[0]=1
    	if(n==1) return b;
    	int lim=2;
    	for(;lim<n;lim<<=1){
    		b.resize(lim);poly c=log(b);
    		c[0]=add(1+a[0],mod-c[0]);
    		for(int i=1;i<lim;++i) c[i]=add(a[i],mod-c[i]);
    		c.resize(lim<<1),NTT(c,0);
    		b.resize(lim<<1),NTT(b,0);
    		for(int i=0;i<lim<<1;++i) b[i]=mul(c[i],b[i]);
    		NTT(b,1),b.resize(lim);
    	}
    	b.resize(lim);poly c=log(b);
    	c[0]=add(1+a[0],mod-c[0]);
    	for(int i=1;i<n;++i) c[i]=add(a[i],mod-c[i]);
    	c.resize(lim<<1),NTT(c,0);
    	b.resize(lim<<1),NTT(b,0);
    	for(int i=0;i<lim<<1;++i) b[i]=mul(c[i],b[i]);
    	NTT(b,1),b.resize(n);
    	return b;
    }
    poly operator*(poly a,poly b){
    	int n=a.size()-1,m=b.size()-1;
    	int lim=1<<(int)ceil(log2(n+m+1));
    	a.resize(lim),NTT(a,0);
    	b.resize(lim),NTT(b,0);
    	for(int i=0;i<lim;++i) a[i]=mul(a[i],b[i]);
    	NTT(a,1),a.resize(n+m+1);
    	return a;
    }
    
    poly solve(int n){
    	poly f{0,1};
    	if(n==2) return f;
    	int lim=4;
    	for(;lim<2*n;lim<<=1){ // edit 1
    		f.resize(lim);
    		poly g=f;
    		NTT(g,0);
    		for(int i=0;i<lim;++i) g[i]=mul(g[i],g[i]);
    		NTT(g,1);
    		poly q=g;
    		poly h(lim);
    		for(int i=0;i<lim;++i){
    			g[i]=add(add(f[i],f[i]),mod-g[i]);
    			h[i]=f[i]?mod-add(f[i],f[i]):0;
    		}
    		h[0]=add(h[0],2);
    		h=~h;
    		g.resize(lim<<1),NTT(g,0);
    		h.resize(lim<<1),NTT(h,0);
    		for(int i=0;i<lim<<1;++i) g[i]=mul(g[i],h[i]);
    		NTT(g,1),g.resize(lim);
    		h.resize(lim);
    		g=exp(g);
    		for(int i=lim-1;i>=1;--i) g[i]=g[i-1];
    		g[0]=0;
    		for(int i=0;i<lim;++i){
    			h[i]=add(add(g[i],g[i]),mod-add(f[i],f[i]));
    			q[i]=add(q[i],mod-add(f[i],f[i]));
    		}
    		q[0]=add(q[0],1);
    		q=~q;
    		q[0]=add(q[0],1);
    		q.resize(lim<<1),NTT(q,0);
    		g.resize(lim<<1),NTT(g,0);
    		for(int i=0;i<lim<<1;++i) q[i]=mul(q[i],g[i]);
    		NTT(q,1),q.resize(lim);
    		g.resize(lim);
    		q[0]=add(q[0],mod-2);
    		q=~q;
    		q.resize(lim<<1),NTT(q,0);
    		h.resize(lim<<1),NTT(h,0);
    		for(int i=0;i<lim<<1;++i) q[i]=mul(q[i],h[i]);
    		NTT(q,1),q.resize(lim);
    		h.resize(lim);
    		for(int i=0;i<lim;++i) f[i]=add(f[i],mod-q[i]);
    	}
    	f.resize(n);
    	return f;
    }
    int main(){
    	omg[0][0]=1,omg[0][1]=fpow(3,(mod-1)/N);
    	omg[1][0]=1,omg[1][1]=fpow(omg[0][1],mod-2);
    	fac[0]=fac[1]=1;
    	inv[0]=inv[1]=1;
    	ifac[0]=ifac[1]=1;
    	for(int i=2;i<N;++i){
    		omg[0][i]=mul(omg[0][i-1],omg[0][1]);
    		omg[1][i]=mul(omg[1][i-1],omg[1][1]);
    		fac[i]=mul(fac[i-1],i);
    		inv[i]=mul(mod-mod/i,inv[mod%i]);
    		ifac[i]=mul(ifac[i-1],inv[i]);
    	}
    	poly f=solve(N/2);
    	for(int i=1;i<N/2;++i) f[i]=mul(f[i],fac[i-1]);
    	for(int T=read<int>();T--;) printf("%d
    ",f[read<int>()]);
    	return 0;
    }
    

    荒漠计数

    荒漠是一张每个极大连通分量都是一个仙人掌无向图。

    (n) 个点的有标号荒漠个数。结果对 (998244353) 取模。

    (n leq 10^5)

    题解

    显然只需要把上一题的 (F(x)) 做个 (exp) 即可。

    时间复杂度 (O(n log n))

    int n=read<int>();
    poly f=solve(n+1);
    for(int i=1;i<=n;++i) f[i]=mul(f[i],inv[i]);
    f=exp(f);
    int ans=mul(f[n],fac[n]);
    printf("%d
    ",ans);
    
  • 相关阅读:
    DDD 领域驱动设计-谈谈 Repository、IUnitOfWork 和 IDbContext 的实践
    UVA10071 Back to High School Physics
    UVA10071 Back to High School Physics
    UVA10055 Hashmat the Brave Warrior
    UVA10055 Hashmat the Brave Warrior
    UVA458 The Decoder
    UVA458 The Decoder
    HDU2054 A == B ?
    HDU2054 A == B ?
    POJ3414 Pots
  • 原文地址:https://www.cnblogs.com/autoint/p/12179436.html
Copyright © 2011-2022 走看看