符号化方法

OI wiki 新增加的一页,在 GF 计数领域非常有用,所以总结一下。

一些符号约定

符号化方法是把组合对象(比如树,字符串,图等我们关心它组合意义的东西)转化为 GF 形式表达的一种方法,考虑把在这些组合对象组成的集合上进行的操作,变成在 GF 上进行的操作,从而大大提升效率。一般地,我们定义组合类:

(A,||)

其中 A 为组合对象组成的集合,|| 是一个单元操作,把一个组合对象映射为一个非负整数。举个例子,比如对于一棵树,我们关心它的结点数,所以就定义 |t|t 这棵树的结点数量。我们定义 An={αA||α|=n}

对于组合类 (A,||) ,其对应的 OGF 为:

A(z)=αAz|α|=n0anzn

对应的 EGF 为:

A^(z)=αAz|α||α|!=n0anznn!

其中 an=card(An)card 表示集合的基数。一般来说,OGF 用于无标号的情况,EGF 用于有标号的情况。

定义中性对象 ϵ 满足 |ϵ|=0,和中性集合 E={ϵ},其对应的 OGF,EGF 为:

E(z)=E^(z)=1

定义原子对象 满足 ||=1,和原子集合 Z={},其对应的 OGF,EGF 为:

Z(z)=Z^(z)=z

显然我们能得到结论,A,都有 AA×EE×A,其中我们称两个组合集 A,B 满足 AB 当且仅当它们不平凡同构。

无标号

本部分介绍的所有操作是基于无标号的,所以对应的 GF 均采用 OGF。

不相交并

对于两个组合类的并 A,B,如果我们单纯将它记为:

A+B

即简单的拼接,如果 AB,就会与不相交的前提相违背。所以我们把它记为:

(E1×A)+(E2×B)

即给两个乘上不同的中性对象,不改变集合的元素本质,但给它们“染上了颜色”,从而不管是否有 AB=,都可以直接拼接。而对应的 OGF 为:

A(z)+B(z)=αAz|α|+βBz|β|=n0(an+bn)zn

即两个集合对应 OGF 的幂级数加法。

笛卡尔积

我们定义两个集合的笛卡尔积 A×B 为:

A×B={(α,β)|αA,βB}

其中如果 γ=(α1,α2,,αn),则我们记 |γ|=|α1|+|α2|++|αn|。通过定义可以找到对应的 OGF:

A(z)B(z)=(α,β)(A×B)z|α|+|β|=n0i+j=naibjzn

即两个集合对应 OGF 的集合幂级数乘法。

序列构造

我们定义一个集合的序列构造 SEQ(C) 为:

SEQ(C)={ϵ}+C+C2+C3+

其中为了保证构造出的集合合理,必须有 C0=。感性理解就是在这个集合里选 0 个的方案,选 1 个的方案,选 2 个的方案等等的并,且选择组成的是序列,即顺序有所谓。对应的 OGF 为:

SEQ(C(z))=n0Cn(z)=11C(z)

循环构造

我们定义一个集合的循环构造 CYC(B) 为:

CYC(B)=SEQ(B)/S

其中 S 为一个等价关系,表示二者循环同构,/S 表示把原集合按照在这个等价意义下等价的元素剔除。感性理解就是在 SEQ(B) 的集合中,去掉循环同构的序列。其对应的 OGF 不那么显然,根据 OI wiki,式子是:

CYC(B(z))=n1φ(n)nln11B(zn)

其中 φ 为欧拉函数。

可重集构造

我们定义一个集合的可重集构造 MSET(A) 为:

MSET(A)=SEQ(A)/R

其中 R 为一个等价关系,表示两个序列对应同一个可重集,/R 表示把原集合按照该等价关系相同的元素剔除。感性来看就是在序列构造的基础上,要求组成的是可重集,即顺序无所谓。除定义外,我们还能得到这样的递推式:

MSET({α0,α1,αn})=MSET({α0,α1,αn1})×SEQ({αn})

表示在原有的生成的可重集内,每个都加入若干个 αn。更进一步,我们能发现:

MSET(A)=αASEQ({α})

因为 SEQ 对应的 OGF 已知,所以 MSET 对应的 OGF 为:

MSET(A(z))=αA(1z|α|)1=n1(1zn)an

不要忘了 SEQ 要求不能出现大小为 0 的元素。

进一步地,我们还能通过取对数继续化简这个 OGF(具体过程可以参考我的 一篇题解):

MSET(A(z))=exp(n1A(zn)n)

可重集构造又被称作 Euler 变换。

幂集构造

我们定义一个集合的幂集构造 PSET(B) 为其所有子集的并。有递推式:

PSET({β0,β1,,βn})=PSET({β0,β1,,βn1})×({ϵ,βn})

即剩下一个元素可以选,也可以不选。进一步地,我们有:

PSET(B)=βB({ϵ,β})

对应的 OGF 为:

PSET(B(z))=βB(1+z|β|)=n1(1+zn)bn

可以发现与 MSET 的非常像,仅仅是换了几个符号,所以另一种 exp 的形式也可以类似地得出:

PSET(B(z))=exp(n1(1)n1B(zn)n)

根据定义容易得到:

PSET(B)MSET(B)

带限制的情况

上面所有的讨论都是基于不限组成部分的情况,但如果要求原序列生成的可重集个数满足某种限制——比如恰为 k——那就无法解决了。定义 K 为上述 SEQ,MSET,PSET,CYC 的其中的一种操作,定义以下三种限制:

Kl(B)Kk(B)Kl..r(B)

为组成部分大于等于 l,恰等于 k,和位于 l..r 中。以 A=Kl..r(B) 为例,这要求:

αA,α={(β0,β1,,βk)|βB},lkr

考虑引入二元 GF 来解决这个问题,如果设 X(α) 表示组成 α 的元素个数,则我们定义 An,k 为:

An,k=card({αA||α|=n,X(α)=k})

则对应的二元 GF 为:

A(z,u)=n,kAn,kukzn=αAuX(α)z|α|

容易发现,Kl..r 的限制只需要提取出 ul..r 的系数,就能得到对应的 OGF,其他两个限制是类似的。

具体来看,对于 SEQ(B)

A(z,u)=n,kAn,kznuk=k0Bk(z)uk=11uB(z)

其中 An,kzn=Bk(z) 是由于对于 SEQ 构造,B(z)k 就表示组成部分为 k 个的 OGF。这样显然有:

[ul]A(z,u)=Bl(z)

对于 MSET(B)

A(z,u)=n(1uzn)bn

只是给每一个元素增加了一个 u,表示这个元素单独的时候表示 1 个元素,从而两个相乘表示拼接的时候也会把 u 的指数相加。可以用类似的方法得到 exp 形式:

A(z,u)=exp(n1unB(zn)n)

exp 展开后即可提取 ul 的系数。

注意在这种情况下,对于 b0 的定义很重要。如果 b0=1,则有可能出现较多的常数项不便于计算。
对于 PSET(B),可以采用类似的思路:

A(z,u)=n(1+uzn)bn

exp 形式类似:

A(z,u)=exp(n1(1)n1unB(zn)n)

依然是把 exp 展开提取系数。

一些例题

loj#6268. 分拆数

定义 f(i) 为把 i 表示成若干正整数之和的方案数,正整数之间的顺序无所谓。求 f(1105),答案对 998,244,353 取模。

如果我们定义组合类 (I,||),其中 I=N+|i|=i,则我们发现题目里给出的分拆其实相当于:

MSET(I)

因为不同的数组成成一个新的组合类,它的大小恰等于各个组分之和,即对于正整数的分拆,又因为顺序无所谓,所以用 MSET。具体算的方法,可以考虑把 MSET 的形式展开一下:

MSET(I(z))=exp(n1I(zn)n)=exp(n1k1ikzknn)

这样每个 ik 会对所有 k 的倍数做贡献,枚举倍数预处理出多项式就可以直接做 exp 了,时间复杂度 O(nlogn)

int main()
{
    int n, m = 1; scanf("%d", &n); while (m <= n) m <<= 1;
    for (int i = 1; i <= n; ++i)
        for (int j = i; j < m; j += i) (F[j] += ksm(j / i, mod - 2)) %= mod;
    getExp(F, G, m);
    for (int i = 1; i <= n; ++i) printf("%d\n", G[i]);
    return 0;
}

洛谷 P5900 无标号无根树计数

n 个点的无标号无根树数量,答案对 998244353 取模。(1n2×105)

发现如果我们求的是有根树,则钦定一个根后,剩下的点其实是分成若干集合,变成子树,且各个子树又是递归结构。所以定义组合类 (T,||),其中 T 表示所有无标号有根树的集合,|t| 表示这棵树结点大小,则:

T={}×MSET(T)

展开成 OGF 就可以做了:

MSET(T(z))=zexp(n1T(zn)n)

具体做法见我的 一篇题解

烷基计数 加强版 加强版

n 个点的每个点度数不超过 4 且根的度数不超过 3 的有根树的数目。(1n105)

这道题一个显然的想法是设组合类 (T,||),与上一道题类似的意义,有等式:

T={}×MSET0..3(T)

不幸的是,如果按照这个等式进行 OGF 的展开,会得到一个非常长的式子,非常不便于计算。注意到这个等式必须要求 MSET0..3 是因为 T 内没有 ϵ 元素,这样的话,满足度数 3 就必须显式表示。而如果我们定义 T^=T+{ϵ},则会有:

T^={ϵ}+{}×MSET3(T^)

而这个式子展开就会方便很多了。考虑把 exp 展开:

MSET3(T(z))=[u3]exp(n1unT(zn)n)=[u3]i0(n1unT(zn)n)ii!=[u3]1+[u3](+u3T(z3)3+)+[u3](uT(z)1+u2T(z2)2+)22+[u3](uT(z)1+)36=T(z3)3+T(z)T(z2)2+T3(z)6

这样能得到:

T(z)=1+z6(2T(z3)+3T(z)T(z2)+T3(z))

可以用半在线卷积或者牛顿迭代分别在 O(nlog2n)O(nlogn) 的时间内求解。

inline void copy(int* f, int* g, int n) { for (int i = 0; i < n; ++i) g[i] = f[i]; }
inline void clear(int* f, int n) { for (int i = 0; i < n; ++i) f[i] = 0; }
inline void cdq(int l, int r)
{
    if (l + 1 == r) return (l % 3 == 1) ? ((A[l] += (ll)A[l / 3] * inv3 % mod) %= mod, void()) : void();
    int mid = (l + r) >> 1; cdq(l, mid); init(r - l);
    copy(A + l, F, mid - l); clear(F + mid - l, lim - mid + l);
    copy(A, G, r - l); clear(G + r - l, lim - r + l);
    for (int i = 0; i < lim; ++i) H[i] = 0;
    for (int i = 0; i < r - l; ++i) if (!(i & 1)) H[i] = A[i / 2];
    NTT(F, lim, 1); NTT(G, lim, 1); NTT(H, lim, 1);
    for (int i = 0; i < lim; ++i)
        F[i] = ((ll)F[i] * H[i] % mod * inv2 % mod + (ll)F[i] * G[i] % mod * G[i] % mod * inv2 % mod * (!l ? inv3 : 1) % mod) % mod;
    NTT(F, lim, mod - 2);
    for (int i = mid; i < r; ++i) (A[i] += F[i - l - 1]) %= mod;
    cdq(mid, r);
}
int main()
{
    int m; scanf("%d", &m); while (n <= m) n <<= 1; A[0] = 1;
    cdq(0, n); printf("%d\n", A[m]); return 0;
}

顺便提一句,如果按照 T={}×MSET0..3(T) 展开得到的是:

T(z)=z6(1+6T(z)+3T2(z)+3T(z2)+3T(z)T(z2)+2T(z3)+T3(z))

如果把 T(z) 换为 T(z)+1,那就跟上面那个式子一样了。所以常数项一般来说处理为 0 会更加方便,甚至有时候必须处理为 0(比如上题无标号无根树,因为没有限制,所以一旦不处理为 0,那常数项就会爆炸)

有标号

本部分介绍的所有内容是基于有标号的,所以对应的 GF 采用 EGF。

一些有标号的例子

对于排列组成的组合类 (P,||),定义 |p| 为排列的长度,则其 EGF 为:

P^(z)=pPz|p||p|!=n0n!znn!=11z

对于圆排列组成的组合类 (C,||),定义 |c| 为圆排列的长度,则其 EGF 为:

C^(z)=cCz|c||c|!=n0(n1)!znn!=ln11z

能看出 expC^(z)=P^(z)

对于图 G=(V,E),且 |E|=0,定义其组合类 (U,||),定义 |u|=|V|,则其 EGF 为:

U^(z)=uUz|u||u|!=n0znn!=ez

这是由于完全没有边的图,相同大小的点集仅对应一个。

集合的有标号乘法

首先我们要知道,把两个元素做有标号乘法会有什么结果。比如 β,γ 为两个有标号元素,则我们定义二者的有标号乘法为这两个元素拼接在一起,并重新标号。而对一个元素重新标号有两种情况,要么是把标号的值域扩大,要么缩小,这导出了对元素有标号乘法两种等价的定义:

βγ={(β,γ)|(β,γ),ρ(β)=β,ρ(γ)=γ}

其中 ρ 表示将标号的值域缩小后的对应。

βγ={(e(β),f(γ))|Im(e)Im(f)=,Im(e)Im(f)={1,2,,|β|+|γ|}}

其中 f,e 表示将标号的值域扩大后的对应,Im(e) 表示对应到的值的集合。可能有点难理解,举个例子吧,比如将一个三角形 123 和一个线段 12 乘在一起会得到 10 个结果:

(123,45),(124,35),(125,34),(134,25),(135,24)(145,23),(234,15),(235,14),(245,13),(345,12)

可以观察到,两个集合 β,γ 大小分别为 n1,n2,如果令 n=n1+n2,则:

card(βγ)=(nn1,n2)

有了这个定义,我们就能得到两个集合的有标号乘法 BC 为:

BC=βB,γC(βγ)

对应的 EGF 操作为:

A^(z)=B^(z)×C^(z)an=|β|+|γ|=n(|β|+|γ||β|,|γ|)=n1+n2=n(nn1,n2)bn1cn2

其中:

(nn1,n2,,nk)=n!n1!n2!nk!

即 EGF 的幂级数乘法。容易发现这个乘法满足结合律:

A(BC)=(AB)C

序列构造

我们定义一个集合的序列构造 SEQ(B) 为:

SEQ(B)={ϵ}+B+B2+B3+

其中 Bn=(BBB),共 nB。定义 k 序列构造 SEQk(B) 为:

SEQk(B)=Bk

可以找到对应的 EGF:

SEQ(B^(z))=11B^(z),SEQk(B^(z))=B^k(z)

SEQ 构造依然要求 B0=

感性理解就是选取 0,1,2, 个元素构成的有标号,顺序有所谓的序列。

集合构造

我们定义一个集合的集合构造 SET(B) 为:

SET(B)={ϵ}+B+SET1(B)+SET2(B)+=k0SETk(B)

其中 k 集合构造 SETk(B)=SEQk(B)/RR 为等价关系,表示两个序列中一个是另一个的排列,/R 表示去掉等价的元素。可以找到对应的 EGF:

SETk(B^(z))=1k!B^k(z),SET(B^(z))=k01k!B^k(z)=exp(B^(z))

注意到所有东西都是有标号的,所以所有的数都是不同的,这样的话,MSET,PSET 都会对应到 SET,即它们都是等价的。感性理解就是选取 0,1,2, 个元素构成的有标号,顺序无所谓的序列。

循环构造

我们定义一个集合的循环构造 CYC(B) 为:

CYC(B)={ϵ}+CYC1(B)+CYC2(B)+=k0CYCk(B)

其中 k 循环构造 CYCk=SEQk/SS 为等价关系,表示两个序列循环同构。这样可以找到对应的 EGF:

CYCk(B^(z))=1kB^k(z),CYC(B^(z))=k01kB^k(z)=ln11B^(z)

通过以上这些操作,我们可以构造出一开始举出的三个例子 U,P,S

P=SEQ(Z),U=SET(Z),C=CYC(Z)

受这个启发,可以构造出的更多操作

满射

满射,即从集合 A 到集合 B 的一种函数,且每个值至少用到一次。我们定义满射集合 R 为:

R=SEQ{SET1(Z)}

如果给出一个 r1,我们定义 Rn(r) 为从 [1n][1r] 的满射的集合,一个例子 R9(5) 的元素之一:

ϕ=(12,21,32,43,55,63,75,83,94)

注意如果把 94 换为 93ϕ 就不是个满射。此外,我们定义:

R(r)=nRn(r)

注意到 R(r) 可以用一个 r 元组集合,且它们的并集是 A 集合表示:

(ϕ1(1),ϕ1(2),,ϕ1(r))

B 集合对应的 A 集合的元素的集合,上面举的例子就是:

({2},{1,3},{4,6,8},{9},{5,7})

这样就可以找到对应的 EGF 了:

R(r)=SEQr{SET1(Z)}R^(r)(z)=(ez1)r

这样 n![zn]R^(r)=Rn(r),二项式定理爆拆:

Rn(r)=n![zn]j=0r(rj)(1)je(rj)z=j=0r(rj)(1)j(rj)n

注意到 R=SEQ(SET1(Z)),这样可以导出:

R^(z)=12ez

简单推导一下:

R^(z)=121112ez=l0elz2l+1

可以得到:

Rn=n![zn]R^(z)=12l0ln2l

分割集合

定义 Sn(r) 表示把集合 {1,2,,n} 分成 r 个不相交集合的方案数,定义 S(r)=nSn(r),这个组合集对应的元素为一种分割,分割的每一部分被叫做一个块。而一个分割可以被一个有标号类的集合表示(每个代表一个块),所以有:

S(r)=SETr{SET1(Z)}S^(r)(z)=1r!(ez1)r

可以发现,Sn(r)=1r!Rn(r)。从组合意义可以看出,一个 r 分割恰好对应 r!r 满射,两个满射在分割意义下是等价的,当且仅当一个是另一个的排列。

容易发现,分割数跟第二类斯特林数有很大的关系,即:

Sn(r)={nr}

根据第二类斯特林数的定义可以得出。所以有:

Rn=r0r!{nr},Sn=r0{nr}

观察到 Sn 其实就是贝尔数。

注意到 S=SET{SET1(Z)},这样可以导出:

S^(z)=eez1

简单推导一下:

S^(z)=1eeez=1el0elzl!

可以得到:

Sn=n![zn]S^(z)=1el0lnl!

平面图

这个 "Alignments" 我也不知道怎么翻译好,于是就直译了。一个平面图被定义为一个良标号的圆组成的序列,定义 O 为平面图的集合,则显然有:

O=SEQ{CYC(Z)}O^(z)=11ln(1z)1

排列

注意到一个排列其实就是若干圆排列的集合,可以从置换环的角度考虑,这样排列的集合 P 就有:

P=SET{CYC(Z)}SEQ(Z)

能导出 EGF:

P^(z)=exp(ln11z)=11z

接下来就用刚刚的方法推导一些东西吧。

树分为两种,一种是平面树,特点是子树之间有顺序,另一种是非平面树,特点是子树之间无顺序。此外,我们定义集合 ΩN 为树的所有点的出度的集合,其中因为树有叶子,所以一定有 0Ω

对于平面有根树,本质上就是确定根之后,剩下的点分成若干部分变成子树,然后递归下去,所以对于平面有根树的集合 A 有:

A=ZSEQΩ(A)

这样对应的 EGF 为:

A^(z)=zwΩA^w(z)

容易发现这个和不带标号的平面有根树很像,具体来讲,不带标号的平面有根树个数为:

1n!An

原因根据组合意义显然。而根据我不会的拉格朗日反演可以得到:

An=n![zn]A^(z)=(n1)![un1](wΩuw)n

而对于非平面有根树,思路类似,对于它的集合 T,我们有:

T=ZSETΩ(T)

这样对应的 EGF 为:

T^(z)=zwΩT^w(z)w!

注意到如果 Ω=N,则有:

T^(z)=zeT^(z)

可与通过我不会的拉格朗日反演得到:

Tn=nn1

如果我们考虑森林,其实就是把若干个树组成一个森林,且顺序无所谓,所以森林的集合 F 为:

F=SET{T}

F^(z)=expT^(z)

写在最后

本篇文章参考 Analytic Combinatorics 这本书的第一,二章,对原文内容做了很大简化,有需要的同学可以找来原书看。由于本人数学很差,所以如果有错还请请喷并指出qwq

posted @   zhiyangfan  阅读(541)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示