zoukankan      html  css  js  c++  java
  • LOJ6538 烷基计数

    题目传送门

    分析:
    这牛顿迭代真离谱
    首先求烷基的话我们至少可以先找到根的位置
    然后找一个生成函数(f)表达它
    相当于每个点除了父亲还可以连出三个儿子
    于是(f_n=sum_{i+j+k+1=n}f_{i}f_{j}f_{k})
    空树时(f_0=1)
    这个是没有考虑同构,同构时结合polya定理,置换大小为6
    手玩一下:
    (f(x)=xfrac{f^3(x)+3f(x)f(x^2)+2f(x^3)}{6})
    怎么求啊。。。牛顿迭代走起来
    (f_0(x))时,我们能够知道(f_0(x^2),f_0(x^3))
    套用式子(f(x)=f_0(x)-frac{G(f_0(x))}{G'(f_0(x))})
    化简:

    [f(x)=f_0(x)-frac{x(f_0^3(x)+3f_0(x)f_0(x^2)+2f_0(x^3))-6f_0(x)+6}{3f_0^2(x)+3f_0(x^2)-6} ]

    NTT大礼包。。。

    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    
    #define maxn 2000005
    #define MOD 998244353
    
    using namespace std;
    
    inline int getint()
    {
    	int num=0,flag=1;char c;
    	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
    	return num*flag;
    }
    
    int F[maxn],rev[maxn];
    
    inline int upd(int x){return x<MOD?x:x-MOD;}
    inline int ksm(int num,int k)
    {
    	int ret=1;
    	for(;k;k>>=1,num=1ll*num*num%MOD)if(k&1)ret=1ll*ret*num%MOD;
    	return ret;
    }
    inline void getrev(int len)
    {for(int i=0;i<len;i++)rev[i]=(rev[i>>1]>>1)|(i&1?len>>1:0);}
    inline void NTT(int *A,int len,int opt)
    {
    	for(int i=0;i<len;i++)if(i<rev[i])swap(A[i],A[rev[i]]);
    	for(int i=1;i<len;i<<=1)
    	{
    		int wn=ksm(3,(MOD-1)/(i<<1));
    		if(!~opt)wn=ksm(wn,MOD-2);
    		for(int j=0;j<len;j+=(i<<1))for(int k=0,w=1;k<i;k++,w=1ll*w*wn%MOD)
    		{
    			int x=A[j+k],y=1ll*A[i+j+k]*w%MOD;
    			A[j+k]=upd(x+y),A[i+j+k]=upd(x-y+MOD);
    		}
    	}
    	if(!~opt)for(int i=0,Inv=ksm(len,MOD-2);i<len;i++)A[i]=1ll*A[i]*Inv%MOD;
    }
    
    inline void getinv(int *A,int *B,int n)
    {
    	static int T[maxn];
    	for(int i=0;i<(n<<1);i++)B[i]=0;
    	B[0]=ksm(A[0],MOD-2);
    	for(int len=2;len<=n;len<<=1)
    	{
    		for(int i=0;i<len;i++)T[i]=A[i],T[i+len]=0;
    		getrev(len<<1);
    		NTT(T,len<<1,1),NTT(B,len<<1,1);
    		for(int i=0;i<(len<<1);i++)B[i]=1ll*B[i]*upd(2-1ll*T[i]*B[i]%MOD+MOD)%MOD;
    		NTT(B,len<<1,-1);
    		for(int i=len;i<(len<<1);i++)B[i]=0;
    	}
    }
    inline void solve(int n)
    {
    	static int G[maxn],H[maxn],S[maxn],C[maxn],T[maxn];
    	F[0]=1;
    	for(int i=2;i<=n;i<<=1)
    	{
    		for(int j=0;j<i;j++)T[j]=F[j],S[j]=C[j]=T[j+i]=S[j+i]=C[j+i]=0;
    		for(int j=0;j<i;j+=2)S[j]=F[j/2];
    		for(int j=0;j<i;j+=3)C[j]=F[j/3];
    		getrev(i<<1);
    		NTT(T,i<<1,1),NTT(S,i<<1,1);
    		for(int j=0;j<(i<<1);j++)G[j]=1ll*T[j]*(1ll*T[j]*T[j]%MOD+3ll*S[j])%MOD,H[j]=3*(1ll*T[j]*T[j]+S[j])%MOD;
    		NTT(G,i<<1,-1),NTT(H,i<<1,-1);
    		for(int j=i;j<(i<<1);j++)G[j]=H[j]=0;
    		for(int j=i-1;j;j--)G[j]=((1ll*G[j-1]+2ll*C[j-1]-6ll*F[j])%MOD+MOD)%MOD,H[j]=H[j-1];
    		G[0]=0,H[0]=MOD-6;
    		NTT(G,i<<1,1),getinv(H,T,i),NTT(T,i<<1,1);
    		for(int j=0;j<(i<<1);j++)G[j]=1ll*G[j]*T[j]%MOD;
    		NTT(G,i<<1,-1);
    		for(int j=0;j<i;j++)F[j]=(F[j]-G[j]+MOD)%MOD;
    	}
    }
    int main()
    {
    	int len=1,n=getint();
    	while(len<=n)len<<=1;
    	solve(len);
    	printf("%d
    ",F[n]);
    }
    

  • 相关阅读:
    进程锁和进程池(附线程池)
    Python多进程
    queue队列
    随笔:python3+yagmail邮件发送,简单易操作
    随笔:用python的pip命令时却显示没有提供命令:Did not provide a command
    随笔:python+selenium+unittest用qq邮箱上传文件并发送邮件
    随笔:用HtmlTestRunner生成报告
    随笔:Linux里mysql的tar包安装
    Performance Testing 前期准备以及场景设计
    Performance Testing 入门小结
  • 原文地址:https://www.cnblogs.com/Darknesses/p/13155136.html
Copyright © 2011-2022 走看看