LG5900 无标号无根树计数

有依赖的辅助多项式分治卷积

\[
g_n=\bigoplus_{i=1}^nf_i\f_n=\sum_{i=1}^{n-1}f_ig_{n-i}
\]

已知 \(f_0=g_0=0,f_1=1\),求 \(f_2\sim f_n\)。对 \(998244353\) 取模。

\(n \leq 10^5\)。

题解

这类问题的特点:

  1. 只有 \(f_1\sim f_n\) 都求出后,\(g_n\) 才能被算出。
  2. 卷积的时候不需要 \(g_n\)。

普通的分治卷积策略是:

\[
(f_l\sim f_{mid})\times (g_1\sim g_{r-l}) \rightarrow (f_{mid+1}\sim f_r)
\]

在这个问题中,当 \(l=1\) 的时候,\(g_{r-l}\) 未被算出。所以不能这样卷积。

特殊的分治卷积策略是:

  1. \(l=1\) 时,

    \[
    (f_l\sim f_{mid})\times (g_l\sim g_{mid})\rightarrow (f_{mid+1}\sim f_r)\ \]

    这样计算的话只有 \(f_{mid+1}\) 的结果是准确的。其余的不仅没有考虑 \(f_{mid+1}\sim f_{i-1}\) 对 \(f_{i}\) 的贡献,还没有考虑 \(g_{mid+1}\sim g_{i-1}\) 对它的贡献。

  2. \(l>1\) 时,

    \[
    \left.
    \begin{align*}
    (f_l\sim f_{mid})\times (g_1\sim g_{r-l})\ (g_l\sim g_{mid})\times (f_1\sim f_{r-l})
    \end{align*}
    \right\}
    \rightarrow (f_{mid+1}\sim f_r)
    \]
    这个时候 \(g_{r-l}\) 和 \(f_{r-l}\) 都被算出来了,刚好可以补全差值。

时间复杂度 \(O(n \log^2 n)\)。

无根树计数

求 \(n\) 个点的无标号无根树数量,答案对 \(998244353\) 取模。

\(n \leq 2\times 10^5\)。

https://www.luogu.com.cn/blog/wengweijie/solution-p5900

欧拉变换简介

为了方便,这里介绍一下幂级数的欧拉变换 \(\mathcal{E}\)。欧拉变换的其中一个定义式如下:

\[
\mathcal{E}(F(x))=\prod_{i=1}^\infty\left(\frac{1}{1-x^i}\right)^{f_i}
\]

这个变换类似于EGF中的 \(\exp\)。

\[
\exp F(x)=\sum_{i=0}^\infty \frac{F^i(x)}{i!}
\]

EGF的 \(\exp\) 具有的组合意义是:将 \(1\sim n\) 分成若干非空组,大小为 \(i\) 的组内部具有 \(f_i\) 中方案,问最后的总方案数。

而欧拉变换就是去除了这个 \(1\sim n\) 的标号的方案数,去掉标号会导致“如果两个组大小和内部方案均相同,则它们不可区分”。

因此欧拉的第一个定义式的意思就是说大小为 \(i\) 的每种内部方案都可以选若干个,每种内部方案的生成函数都是 \(\frac{1}{1-x^i}\)。

现在使用指数、对数方法可以得到欧拉变换的第二个定义式。

\[
\mathcal{E}(F(x))=\exp\left(\sum_{i=1}^\infty\ln\left(\frac{1}{1-x^i}\right)^{f_i}\right)\=\exp\left(\sum_{i=1}^\infty-f_i\ln(1-x^i)\right)\=\exp\left(\sum_{i=1}^\infty f_i\sum_{j=1}^\infty\frac{x^{ij}}j\right)\=\exp\left(\sum_{j=1}^\infty\frac 1j\sum_{i=1}^\infty f_ix^{ij}\right)=\exp\left(\sum_{j=1}^\infty\frac{F(x^j)}j\right)
\]

无标号有根树计数

容易发现,给定根以后,所有的子树可以理解成构成总大小为 \(n-1\) 的若干个组。

因此我们需要解的方程即:

\[
F(x)=x\mathcal{E}(F(x))=x\exp\left(\sum_{i=1}^\infty -f_i\ln(1-x^i)\right)\\]

有 \(\exp\) 不好处理,求 \(\ln\)。

\[
\ln F(x)=\ln x+\sum_{i=1}^\infty -f_i\ln(1-x^i)
\]

\(\ln\) 也不好处理,求导。

\[
\frac{F'(x)}{F(x)}=\frac{1}{x}+\sum_{i=1}^\infty if_i\frac{x^{i-1}}{1-x^i}
\]

通分,两侧都乘上 \(xF(x)\)。

\[
xF'(x)=F(x)+F(x)\sum_{i=1}^\infty if_i\frac{x^i}{1-x^i}\\]

其中

\[
\sum_{i=1}^\infty if_i\frac{x^i}{1-x^i}=\sum_{i=1}^\infty if_i\sum_{j=1}^\infty x^{ji}=\sum_{j=1}^\infty x^jF'(x^j)
\]

设 \(G(x)=\sum_{i=1}^\infty x^iF'(x^i)\)。可以观察到

\[
g_n=\sum_{i|n}if_i\nf_n=f_n+\sum_{i=1}^{n-1}f_ig_{n-i}\f_n=\frac{1}{n-1}\left(\sum_{i=1}^{n-1}f_ig_{n-i}\right)
\]

其中 \(f_1=1\)。此时便可以使用“有依赖的辅助多项式分治卷积”解决这个问题。

无标号无根树计数

这个问题思路大概是:用有根树的方案减去根不是重心的方案。

  1. 当 \(n\) 是奇数时:

    如果根不是重心,必然存在恰好一个子树,它的大小超过 \(\left\lfloor\frac n2\right\rfloor\)(设它的大小为 \(k\)),那么这个子树和这棵子树以外的其他点的方案数恰好为 \(f_kf_{n-k}\)(可以看成两棵有根树)。

    因此答案为

    \[
    ans=f_n-\sum_{k=\lfloor n/2\rfloor+1}^{n-1}f_kf_{n-k}
    \]

  2. 当 \(n\) 是偶数时:

    出现的问题是,有可能存在两个重心,且其中一个是根(即存在一棵子树大小恰为 \(\frac n2\))。

    那么如果这个子树和剥离该子树后的树完全相同,这样的方案在 \(f_n\) 只会计算一次,即不需要减去;如果这个子树和另一棵树不相同,会被统计两次,需要减掉一次。

    因此偶数时额外减掉的方案数为 \(\binom{f_{n/2}}2\)。

至此,这个问题在 \(O(n\log^2n)\) 的时间复杂度内解决。

CO int N=524288;
int omg[2][N],rev[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,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;
}

int n,inv[N],f[N],g[N];

void solve(int l,int r){
    if(r-l+1<=100){
        for(int i=l;i<=r;++i){
            for(int j=l;j<i;++j){
                f[i]=add(f[i],mul(f[j],g[i-j]));
                if(l==1) continue;
                f[i]=add(f[i],mul(g[j],f[i-j]));
            }
            f[i]=mul(f[i],inv[i-1]);
            int v=mul(f[i],i);
            for(int j=i;j<=n;j+=i) g[j]=add(g[j],v);
        }
        return;
    }
    int mid=(l+r)>>1;
    solve(l,mid);
    if(l==1){
        poly a=poly(f+1,f+mid+1)*poly(g+1,g+mid+1);
        for(int i=mid+1;i<=r;++i) f[i]=add(f[i],a[i-2]);
    }
    else{
        poly a=poly(f+l,f+mid+1)*poly(g+1,g+r-l+1);
        poly b=poly(g+l,g+mid+1)*poly(f+1,f+r-l+1);
        for(int i=mid+1;i<=r;++i) f[i]=add(f[i],add(a[i-l-1],b[i-l-1]));
    }
    solve(mid+1,r);
}

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);
    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]);
    }
    read(n);
    inv[0]=inv[1]=1;
    for(int i=2;i<N;++i) inv[i]=mul(mod-mod/i,inv[mod%i]);
    f[1]=1,solve(1,n);
    int ans=f[n];
    for(int i=n/2+1;i<n;++i) ans=add(ans,mod-mul(f[i],f[n-i]));
    if(n%2==0) ans=add(ans,mod-(int64)f[n/2]*(f[n/2]-1)/2%mod);
    printf("%d\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/autoint/p/12178270.html

时间: 2024-10-09 00:03:32

LG5900 无标号无根树计数的相关文章

无标号树的计数原理(组合计数,背包问题,隔板法,树的重心)

闲话 一个计数问题入门级选手来搞这种东西 最初的动力来自高一化学课有机物(滑稽).<同步导练>出了个这样的选择题. 一个结构极其庞大的烷烃(二十几个碳原子),求它的主链长度. 这不是个求树的直径的裸题么?!OI选手扫两眼就出来了,然而别的同学费劲心思找完了还是错的. 于是第一次在常规课中体验到作为OIer的优越感...... 又是一节课,芙蓉姐开始要我们画己烷.庚烷的同分异构体?! 这不是等于要求节点数为\(n\),点度数不超过\(4\)的无标号的无根树个数吗?没见过,但还是有一点DP思想,蒟

[P4841]无向连通图计数与生成函数

今天对于生成函数有了一个初步的认识:生成函数是一个多项式,我们令他为F.则F=a0+a1*x+a2*x^2+a3*x^3........an*x^n我们在数组中保留的则是a0,a1,a2........an生成函数有这样的性质:F^x(an)=sigma (b是一个n的自然数分解)a[b1]*a[b2]*a[b3]......所以在P4841中,生成函数有了用武之地.对于一张无向图,他一定是由若干个联通块构成的.所以,若令无标号无向图的方案数的生成函数为F,无标号无向联通图的方案数的生成函数为G

【XSY1295】calc n个点n条边无向连通图计数 prufer序列

题目大意 求\(n\)个点\(n\)条边的无向连通图的个数 \(n\leq 5000\) 题解 显然是一个环上有很多外向树. 首先有一个东西:\(n\)个点选\(k\)个点作为树的根的生成森林个数为: \[ \binom{n}{k}\times n^{n-k-1}\times k \] 前面\(\binom{n}{k}\)是这些根的选编号的方案数,后面是prufer序列得到的:前面\(n-k-1\)个数可以是\(1\)~\(n\),第\(n-k\)个数是\(1\)~\(k\). 我的理解是:每个

有无标号计数

有标号有根树 \(n^{n-1}\) 有标号无根树 \(n^{n-2}\) 标号为\(i\)的点度数为\(a_i\)的无根树 \(\frac{(n-2)!}{\prod(a_i-1)!}\) 无标号有根树 设\(f_n\)表示n个点的无标号有根树数量 ,\(f\)的生成函数为\(F(x)\) 我们考虑去除根节点的各个子树,可以分成若干个子问题,枚举大小为\(k\)的子树有多少个,再枚举大小为\(k\)的子树的\(f_k\)个形态选多少个 \[ \begin{split} [x^{n}]F(x)&

图的计数

无标号计数与带标号计数 无标号就是在观测上不考虑个体的差异, 带标号就是在观测上考虑个体的差异. 对于无标号计数, 我们可以按照某种关键值, 给所有的元素进行定序, 所有无标号计数等价于定序计数. 对于带标号计数, 我们可以任意设置关键值, 所以带标号计数等价于不定序计数. 最常见的例子就是组合与排列, 它们还满足一组特殊的关系: 组合数 * n! = 排列数. 有向图 / 无向图 带标号无向图的 度数的K次方 的和 分析 $ans = n \sum_{d = 0} ^ {n - 1} \bin

组合计数小练

组合数学什么的,最有趣了呢-- [51nod 1251] Fox序列的数量 题意 求满足以下条件的序列数目: 序列长度为 $ n $ ,每个元素都属于 $ [1,m] \cap Z $ : 这个序列单调不降: 这个序列出现次数最多的数是唯一的. 数据范围: $ 1≤n,m≤100000 $ ,答案对 $ 1e9+7 $ 取模 题解 先枚举出现次数最多的数的出现次数 $ k $ ,我们要计算的是 $ x_1+x_2+...+x_{m-1}=n-k, ; x_i≤k-1 $ 的非负整数解数目. 可以

训练记录PART1

11/05 bestcoder #93 C 等价于给出很多环,等概率选择N个点,收益为出现过点的环的环长lcm.不同的环只有 \(\sqrt {26}=6\) 个,用\(f_S\)表示点出现在状态为S的那些环里的选取总数,DP一下即可. bestcoder #93 D 考虑meet in the middle.推一下式子,设左侧选的数和为\(A_{left}t\),两两乘积之和为\(B_{left}\),那么满足\(B_{left}+B_{right}+A_{left}*A_{right}>=0

[BZOJ1005](HNOI 2008)明明的烦恼

Description 自从明明学了树的结构,就对奇怪的树产生了兴趣...... 给出标号为1到N的点,以及某些点最终的度数,允许在任意两点间连线,可产生多少棵度数满足要求的树? Input 第一行为N(0 < N < = 1000),接下来N行,第i+1行给出第i个节点的度数Di,如果对度数不要求,则输入-1 Output 一个整数,表示不同的满足要求的树的个数,无解输出0 Sample Input 3 1 -1 -1 Sample Output 2 HINT 两棵树分别为1-2-3;1-3

Codeforces 506E Mr. Kitayuta&#39;s Gift - 动态规划 - 矩阵

题目传送门 通往Codeforces的航线 通往vjudge的航线 题目大意 给定一个仅包含小写字母的串$s$,要求插入恰好$n$个小写字母字符,使得新串为回文串.问这样得到的新串有多少个是本质不同回文串. $1\leqslant |s| \leqslant 200,1 \leqslant n \leqslant 10^{9} $ 神题orz...orz...orz.Petr orz...orz...orz. 好了开始扯正题了. 任意位置插入并不太好处理.可以转化一下这个问题,求一个长度为$|s