其他分享
首页 > 其他分享> > LOJ6538 烷基计数

LOJ6538 烷基计数

作者:互联网

题目传送门

分析:
这牛顿迭代真离谱
首先求烷基的话我们至少可以先找到根的位置
然后找一个生成函数\(f\)表达它
相当于每个点除了父亲还可以连出三个儿子
于是\(f_n=\sum_{i+j+k+1=n}f_{i}f_{j}f_{k}\)
空树时\(f_0=1\)
这个是没有考虑同构,同构时结合polya定理,置换大小为6
手玩一下:
\(f(x)=x\frac{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\n",F[n]);
}

标签:frac,int,ret,3f,计数,num,LOJ6538,include,烷基
来源: https://www.cnblogs.com/Darknesses/p/13155136.html