如果这篇博客帮助到你,可以请我喝一杯咖啡~
CC BY-NC-SA 4.0 (除特别声明或转载文章外)
烷基计数
求 n 个点的每个点度数不超过 4 且根的度数不超过 3 的无标号有根树的数目。
设答案的 OGF 为 A(x),考虑根的子节点,使用 Burside 引理得到:
A(x)=x6A(x)3+3A(x2)A(x)+2A(x3)+1考虑牛顿迭代,设 A∗(x) 为 modx2n 的答案。
F(A(x))=x6A(x)3+3A(x2)A(x)+2A(x3)+1−A(x)=0A(x)=A∗(x)−F′(A∗(x))F(A∗(x))(modxn)F′(A(x))=x2A(x)2+A(x2)−1烯烃计数
断开碳-碳双键两边是根节点度数不超过 2,其他点子节点个数小于等于 3 的无标号有根树。
这棵树的 OGF 为 P(x):
P(x)=x2A(x)2+A(x2)+1烯烃的 OGF 为 G(x):
G(x)=x2(P(x)−1)2+P(x2)−1#include<cstdio>
#include<algorithm>
int const mod=998244353,g=3,gi=998244354/3,inv2=998244354/2,inv6=998244354/6,maxn=800010;
int pow(int x,int y){
int res=1;
while(y){
if(y&1)res=1ll*x*res%mod;
x=1ll*x*x%mod,y>>=1;
}
return res;
}
struct NTT{
int r[maxn],lim;
NTT():r(),lim(){}
void getr(int const &li){
lim=li;
for(int i=0;i<lim;i++)r[i]=(r[i>>1]>>1)|((i&1)*(lim>>1));
}
void operator ()(int *a,int const &type)const{
for(int i=0;i<lim;i++)if(i<r[i])std::swap(a[i],a[r[i]]);
for(int mid=1;mid<lim;mid<<=1){
int rt=pow(type==1?g:gi,(mod-1)/(mid<<1));
for(int r=mid<<1,j=0;j<lim;j+=r){
int p=1;
for(int k=0;k<mid;k++,p=1ll*p*rt%mod){
int x=a[j+k],y=1ll*p*a[j+k+mid]%mod;
a[j+k]=(x+y)%mod,a[j+mid+k]=(x-y+mod)%mod;
}
}
}
if(type==-1)for(int p=pow(lim,mod-2),i=0;i<lim;i++)a[i]=1ll*a[i]*p%mod;
}
}ntt;
void inv(int const *a,int *ans,int const &m){
static int tmp[maxn];
for(int i=0;i<m<<1;i++)tmp[i]=ans[i]=0;
ans[0]=pow(a[0],mod-2);
for(int n=2,lim;n<=m;n<<=1){
for(int i=0;i<n;i++)tmp[i]=a[i];
ntt.getr(lim=n<<1);
ntt(tmp,1),ntt(ans,1);
for(int i=0;i<lim;i++)ans[i]=ans[i]*(2-1ll*ans[i]*tmp[i]%mod+mod)%mod;
ntt(ans,-1);
for(int i=n;i<lim;i++)ans[i]=0;
}
}
void solve(int *ans,int const &m){
static int a3[maxn],a2[maxn],a1[maxn],fz[maxn],fm[maxn];
ans[0]=1;
for(int n=2,lim;n<=m;n<<=1){
for(int i=0;i<n<<1;i++)a1[i]=a2[i]=a3[i]=fz[i]=fm[i]=0;
for(int i=0;i<n;i++)a1[i]=ans[i];
for(int i=0;i<n;i+=2)a2[i]=ans[i/2];
for(int i=0;i<n;i+=3)a3[i]=ans[i/3];
ntt.getr(lim=n<<2);
ntt(a1,1);
for(int i=0;i<lim;i++)a1[i]=1ll*a1[i]*a1[i]%mod*a1[i]%mod;
ntt(a1,-1);
for(int i=0;i<n;i++)fz[i]=a1[i],a1[i]=ans[i],fm[i]=a2[i];
for(int i=n;i<lim;i++)a1[i]=0;
ntt.getr(lim=n<<1);
ntt(a1,1),ntt(a2,1);
for(int i=0;i<lim;i++)a2[i]=1ll*a2[i]*a1[i]%mod,a1[i]=1ll*a1[i]*a1[i]%mod;
ntt(a1,-1),ntt(a2,-1);
for(int i=n-1;i;i--)fz[i]=(1ll*inv6*fz[i-1]+1ll*inv2*a2[i-1]+1ll*gi*a3[i-1])%mod;
fz[0]=1;
for(int i=0;i<n;i++)fz[i]=(fz[i]-ans[i]+mod)%mod;
for(int i=n-1;i;i--)fm[i]=1ll*inv2*(a1[i-1]+fm[i-1])%mod;
fm[0]=mod-1;
for(int i=n;i<lim;i++)fz[i]=fm[i]=0;
inv(fm,a1,n);
ntt.getr(lim);
ntt(a1,1),ntt(fz,1);
for(int i=0;i<lim;i++)a1[i]=1ll*a1[i]*fz[i]%mod;
ntt(a1,-1);
for(int i=0;i<n;i++)ans[i]=(ans[i]-a1[i]+mod)%mod;
}
}
int a[maxn],b[maxn],lim=1<<17;
int main(){
solve(a,lim);
for(int i=0;i<lim;i++)b[i]=a[i];
for(int i=0;i<lim;i++)a[i]=0;
for(int i=0;i<lim;i+=2)a[i]=b[i>>1];
ntt.getr(lim<<1);
ntt(b,1);
for(int i=0;i<lim<<1;i++)b[i]=1ll*b[i]*b[i]%mod;
ntt(b,-1);
for(int i=lim-1;i;i--)a[i]=1ll*inv2*(a[i-1]+b[i-1])%mod;
a[0]=0;
for(int i=0;i<lim<<1;i++)b[i]=0;
for(int i=0;i<lim;i+=2)b[i]=a[i>>1];
ntt(a,1);
for(int i=0;i<lim<<1;i++)a[i]=1ll*a[i]*a[i]%mod;
ntt(a,-1);
for(int i=lim-1;~i;i--)a[i]=1ll*inv2*(a[i]+b[i])%mod;
int t;
scanf("%d",&t);
for(int i=2;i<=t;i++)printf("%d\n",a[i]);
return 0;
}