Karry5307
2020-03-26 10:08:57
求
可能是你谷最详细阐明
首先考虑有根树计数,设
现在我们来定义
这里给出另外一种组合解释,如果
但是这个定义式是可以优化的,如果你做过付公主的背包这个题目的话应该对这种优化比较熟悉。我们设
两边求导,得到
做个级数展开
积分回来
交换求和顺序,可以写成这个样子
注意到右边是个点值,所以
于是有
回到无标号有根数的计数上面来,所以我们用生成函数表示可以得到以下式子
这个可以牛迭求出,尽管是
考虑同时求导并且乘上 计算过程给读者留做练习)
设 找规律和目瞪口呆法发现,有
于是有
解出来得到
这个可以分治
接下来考虑把根的影响去掉,这个的话可以考虑枚举重心,用有根树的答案减去根不是重心的答案。
由于当树的大小是偶数的时候可能存在两个重心,所以要分类讨论一下。
当
右边的东西可以随手卷一下。
当
额外减掉的方案为
至此,这个题目就可以用
#include<bits/stdc++.h>
#pragma GCC optimize("Ofast,unroll-loops")
using namespace std;
typedef int ll;
typedef long long int li;
typedef unsigned long long int ull;
const ll MAXN=524291,MOD=998244353,G=3,INVG=332748118;
ll n,cnt,limit;
ll f[MAXN],g[MAXN],tmp[MAXN],tmp2[MAXN],tmp3[MAXN],rev[MAXN<<1],omgs[MAXN<<1];
inline ll read()
{
register ll num=0,neg=1;
register char ch=getchar();
while(!isdigit(ch)&&ch!='-')
{
ch=getchar();
}
if(ch=='-')
{
neg=-1;
ch=getchar();
}
while(isdigit(ch))
{
num=(num<<3)+(num<<1)+(ch-'0');
ch=getchar();
}
return num*neg;
}
inline ll qpow(ll base,ll exponent)
{
li res=1;
while(exponent)
{
if(exponent&1)
{
res=1ll*res*base%MOD;
}
base=1ll*base*base%MOD,exponent>>=1;
}
return res;
}
inline void setupOmg(ll cnt)
{
ll limit=log2(cnt)-1,omg;
omg=qpow(G,(MOD-1)>>(limit+1)),omgs[cnt>>1]=1;
for(register int i=(cnt>>1|1);i!=cnt;i++)
{
omgs[i]=(li)omgs[i-1]*omg%MOD;
}
for(register int i=(cnt>>1)-1;i;i--)
{
omgs[i]=omgs[i<<1];
}
}
inline void NTT(ll *cp,ll cnt,ll inv)
{
static ull tcp[MAXN];
register ll cur=0,x,shift=log2(cnt)-__builtin_ctz(cnt);
if(inv==-1)
{
reverse(cp+1,cp+cnt);
}
for(register int i=0;i<cnt;i++)
{
tcp[rev[i]>>shift]=cp[i];
}
for(register int i=2;i<=cnt;i<<=1)
{
cur=i>>1;
for(register int j=0;j<cnt;j+=i)
{
for(register int k=0;k<cur;k++)
{
x=tcp[j|k|cur]*omgs[k|cur]%MOD;
tcp[j|k|cur]=tcp[j|k]+MOD-x,tcp[j|k]+=x;
}
}
}
for(register int i=0;i<cnt;i++)
{
cp[i]=tcp[i]%MOD;
}
if(inv==1)
{
return;
}
x=MOD-(MOD-1)/cnt;
for(register int i=0;i<cnt;i++)
{
cp[i]=(li)cp[i]*x%MOD;
}
}
inline void conv(ll cnt,ll *f,ll *g,ll *res)
{
static ll tmpf[MAXN],tmpg[MAXN];
for(register int i=0;i<cnt;i++)
{
tmpf[i]=f[i],tmpg[i]=g[i],res[i]=0;
}
ll limit=log2(cnt)-1;
for(register int i=0;i<cnt;i++)
{
rev[i]=(rev[i>>1]>>1)|((i&1)<<limit);
}
NTT(tmpf,cnt,1),NTT(tmpg,cnt,1);
for(register int i=0;i<cnt;i++)
{
res[i]=(li)tmpf[i]*tmpg[i]%MOD;
tmpf[i]=tmpg[i]=0;
}
NTT(res,cnt,-1);
}
inline void calc(ll l,ll r)
{
ll mid=(l+r)>>1;
if(l==1)
{
for(register int i=l;i<=mid;i++)
{
tmp[i-l]=f[i],tmp2[i-l]=g[i];
}
ll cnt=1;
while(cnt<=((r-l)<<1))
{
cnt<<=1;
}
conv(cnt,tmp,tmp2,tmp3);
for(register int i=mid+1;i<=r;i++)
{
f[i]=(f[i]+tmp3[i-l-1])%MOD;
}
for(register int i=0;i<cnt;i++)
{
tmp[i]=tmp2[i]=tmp3[i]=0;
}
return;
}
for(register int i=l;i<=mid;i++)
{
tmp[i-l]=f[i];
}
for(register int i=1;i<=r-l;i++)
{
tmp2[i-1]=g[i];
}
ll cnt=1;
while(cnt<=((r+mid-l-l+1)<<1))
{
cnt<<=1;
}
conv(cnt,tmp,tmp2,tmp3);
for(register int i=mid+1;i<=r;i++)
{
f[i]=(f[i]+tmp3[i-l-1])%MOD;
}
for(register int i=0;i<cnt;i++)
{
tmp[i]=tmp2[i]=tmp3[i]=0;
}
for(register int i=l;i<=mid;i++)
{
tmp[i-l]=g[i];
}
for(register int i=1;i<=r-l;i++)
{
tmp2[i-1]=f[i];
}
conv(cnt,tmp,tmp2,tmp3);
for(register int i=mid+1;i<=r;i++)
{
f[i]=(f[i]+tmp3[i-l-1])%MOD;
}
for(register int i=0;i<cnt;i++)
{
tmp[i]=tmp2[i]=tmp3[i]=0;
}
}
inline void cdqFFT(ll l,ll r)
{
if(l==r)
{
f[l]=l!=1?((li)f[l]*qpow(l-1,MOD-2)%MOD):1;
for(register int i=l;i<=n;i+=l)
{
g[i]=(g[i]+(li)f[l]*l%MOD)%MOD;
}
return;
}
ll mid=(l+r)>>1;
cdqFFT(l,mid),calc(l,r),cdqFFT(mid+1,r);
}
int main()
{
n=read()+1,cnt=1;
while(cnt<=n)
{
cnt<<=1;
}
setupOmg(cnt<<1),cdqFFT(1,cnt),cnt=1,limit=-1;
while(cnt<=(n<<1))
{
cnt<<=1,limit++;
}
for(register int i=0;i<cnt;i++)
{
rev[i]=(rev[i>>1]>>1)|((i&1)<<limit);
tmp[i]=i<=n?f[i]:0;
}
NTT(tmp,cnt,1);
for(register int i=0;i<cnt;i++)
{
tmp[i]=(li)tmp[i]*tmp[i]%MOD;
}
NTT(tmp,cnt,-1);
for(register int i=1;i<=n;i+=2)
{
g[i]=(f[i]-(li)tmp[i]*499122177%MOD+MOD)%MOD;
}
for(register int i=2;i<=n;i+=2)
{
tmp[i]=(tmp[i]-(li)f[i>>1]*f[i>>1]%MOD+MOD)%MOD;
g[i]=(f[i]-(li)tmp[i]*499122177%MOD+MOD)%MOD;
g[i]=(g[i]-(li)f[i>>1]*(f[i>>1]-1)%MOD*499122177%MOD+MOD)%MOD;
}
printf("%d\n",g[n-1]);
}