当前位置: 首页 > news >正文

离散与组合数学 杂记

生成函数

概念

又称母函数把一个无穷数列 {an}\{a_n\}{an}(默认从 000 项起)表示成 G(x)=∑i≥0aixiG(x)=\displaystyle\sum_{i\ge0} a_ix^iG(x)=i0aixi 的函数形式。例如:

  • ai=2ia_i=2^iai=2iG(x)=∑i≥02ixiG(x)=\displaystyle\sum_{i\ge 0} 2^i x^iG(x)=i02ixi
  • ai=1a_i=1ai=1G(x)=∑i≥0xiG(x)=\displaystyle\sum _{i\ge 0} x^iG(x)=i0xi

应用

用来帮助推导数列的通项公式(比如斐波那契数列)也可以作为条件形式以数列形式给出的象征。一个特别的转化:逆运用等比数列求和公式,可以得到:11−ax=∑i≥0aixi\displaystyle\dfrac{1}{1-ax}=\sum_{i\ge0}a^ix^i1ax1=i0aixi,等号左边不带求和符号部分的,称为生成函数的封闭形式。

生成函数的乘法运算有意义,其卷积形式是函数直接相乘。对于 A(x)=∑i≥0aixiA(x)=\displaystyle\sum_{i\ge0}a_ix^iA(x)=i0aixiA(x)=∑i≥0bixiA(x)=\displaystyle\sum_{i\ge0}b_ix^iA(x)=i0bixi
A×B=∑i≥0n(xi∑j=0iajbi−j)A\times B=\sum_{i\ge0}^n\left(x^i\sum_{j=0}^ia_jb_{i-j}\right)A×B=i0n(xij=0iajbij)

洛谷 P10780 BZOJ3028 食物

题意

题目传送门。

思路

根据上文,将这个背包问题转化为,考虑每一种物品拿的个数的生成函数,并用封闭形式表示:

  • 偶数个形如 {1,0,1,0,1,......}\{1,0,1,0,1,......\}{1,0,1,0,1,......}∑k≥0x2k=11−x2\displaystyle\sum_{k\ge 0} x^{2k}=\frac{1}{1-x^2}k0x2k=1x21
  • 000111 个形如 {1,1,0,0,0,......}\{1,1,0,0,0,......\}{1,1,0,0,0,......}1+x1+x1+x
  • 000111222 个形如 {1,1,1,0,0,......}\{1,1,1,0,0,......\}{1,1,1,0,0,......}1+x+x21+x+x^21+x+x2
  • 奇数个形如 {0,1,0,1,0,......}\{0,1,0,1,0,......\}{0,1,0,1,0,......}∑k≥0x2k+1=x∑k≥0x2k=x1−x2\displaystyle\sum_{k\ge 0}x^{2k+1}=x\displaystyle\sum_{k\ge 0} x^{2k}=\frac{x}{1-x^2}k0x2k+1=xk0x2k=1x2x
  • 444 的倍数个类似第一条:∑k≥0x4k=11−x4\displaystyle\sum_{k\ge 0}x^{4k}=\frac{1}{1-x^4}k0x4k=1x41
  • 000111222333 个形如 {1,1,1,0,0,......}\{1,1,1,0,0,......\}{1,1,1,0,0,......}1+x+x2+x31+x+x^2+x^31+x+x2+x3
  • 333 的倍数个类似第一条:∑k≥0x3k=11−x3\displaystyle\sum_{k\ge 0}x^{3k}=\frac{1}{1-x^3}k0x3k=1x31.

全部乘起来,并用二项式定理化简 1+x+x21+x+x^21+x+x21+x+x2+x31+x+x^2+x^31+x+x2+x3
x(1−x)4\frac{x}{(1-x)^4}(1x)4x

考虑推 1(1−x)k=(11−x)k\dfrac{1}{(1-x)^k}=\left(\dfrac{1}{1-x}\right)^k(1x)k1=(1x1)k 是哪个生成函数的封闭形式与该生成函数的第 nnn 项系数,因为 11−ax=∑i≥0aixi\displaystyle\dfrac{1}{1-ax}=\sum_{i\ge0}a^ix^i1ax1=i0aixia=1a=1a=1 时,11−x=1+x+x2+x3+...\dfrac{1}{1-x}=1+x+x^2+x^3+...1x1=1+x+x2+x3+...kkk 次方展开后,相当于选 kkk 个自然数和为 nnn 的方案数:先给 kkk 个数加 111 转化问题为 kkk 个正整数和为 n+kn+kn+k,运用插板法得知方案数为 (n+k−1k−1)\dbinom{n+k-1}{k-1}(k1n+k1)

回到这一题 1(1−x)4\frac{1}{(1-x)^4}(1x)41 的第 n−1n-1n1 项系数为 (n−23)\dbinom{n-2}{3}(3n2),乘回 xxx 后即为答案。代码略。

Polya 计数

等我完全理解完再回来补。先给结论:用 kkk 中颜色给 nnn 个点的环染色方案数为 1n∑i=0n−1kgcd⁡(n,i)\dfrac{1}{n}\displaystyle\sum_{i=0}^{n-1}k^{\gcd(n,i)}n1i=0n1kgcd(n,i),可否感性理解呢?

洛谷 P4980 【模板】Pólya 定理

题意

nnn 种颜色给 nnn 个点染色的方案数。两种方案相同,当且仅当一种方案能够旋转变为“另一方案”。

n≤109n\le 10^9n109

思路

问题是如何快速算出 1n∑i=0n−1ngcd⁡(n,i)\dfrac{1}{n}\displaystyle\sum_{i=0}^{n-1}n^{\gcd(n,i)}n1i=0n1ngcd(n,i)。不妨暴力枚举 nnn 的约数 d=gcd⁡(n,i)d=\gcd(n,i)d=gcd(n,i),变为:
1n∑d∣nndφ(nd)\dfrac{1}{n}\displaystyle\sum_{d|n}n^d\varphi(\frac{n}{d})n1dnndφ(dn)

nnn 太大了不能预处理 φ\varphiφ,记得勤取模。时间复杂度为 T(n)=∑i≥0{O(i)+O(n/i)}=O(n3/4)T(n)=\displaystyle\sum_{i\ge 0}\{O(\sqrt{i})+O(\sqrt{n/i})\}=O(n^{3/4})T(n)=i0{O(i)+O(n/i)}=O(n3/4)(根据主定理推得)。代码略。

第二类斯特林数

为什么先说第二类,因为第二类好像常用一些。

斯特林数将两个典型的模型的方案数求解变成一个类似组合数的东西。

概念

{nm}\begin{Bmatrix} n\\ m \end{Bmatrix}{nm} 表示,将 nnn 个不同的球放进 mmm 个相同的盒子里,且每个盒子都非空的方案数。

其递推式的推导:

  • nnn 单开一个盒子,那么剩下 n−1n-1n1 个球放进 m−1m-1m1 个盒子:{n−1m−1}\begin{Bmatrix} n-1\\ m-1 \end{Bmatrix}{n1m1}
  • nnn 放进非空的 mmm 个盒子:m{n−1m}m\begin{Bmatrix} n-1\\ m \end{Bmatrix}m{n1m}

所以 {nm}={n−1m−1}+m{n−1m}\begin{Bmatrix} n\\ m \end{Bmatrix}=\begin{Bmatrix} n-1\\ m-1 \end{Bmatrix}+m\begin{Bmatrix} n-1\\ m \end{Bmatrix}{nm}={n1m1}+m{n1m}

特别的,{n0}=[n=0]\begin{Bmatrix} n\\ 0 \end{Bmatrix}=[n=0]{n0}=[n=0],中括号表示艾弗森括号。

可以 O(n2)O(n^2)O(n2) 预处理。

应用

先证明其通项公式,发现其满足下降幂性质:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

CF932E Team Work

题意

给定 n,kn,kn,k,求 ∑i=1n(ni)ik\displaystyle\sum_{i=1}^n\dbinom{n}{i}i^ki=1n(in)ik

n≤109n\le 10^9n109k≤5000k\le 5000k5000

思路

把组合数用阶乘拆开,再运用斯特林数下降幂的性质:

∑i=0nn!i!(n−i)!∑j=0k{kj}i!(i−j)!\sum_{i=0}^n\frac{n!}{i!(n-i)!}\sum_{j=0}^k\begin{Bmatrix} k\\ j \end{Bmatrix}\frac{i!}{(i-j)!}i=0ni!(ni)!n!j=0k{kj}(ij)!i!

改变 iiijjj 的枚举顺序,iiijjj 开始到 nnn
∑j=0k{kj}∑i=jnn!(n−i)!(i−j)!\sum_{j=0}^k\begin{Bmatrix} k\\ j \end{Bmatrix}\sum_{i=j}^n\frac{n!}{(n-i)!(i-j)!}j=0k{kj}i=jn(ni)!(ij)!n!

强制变成组合数:
∑j=0k{kj}n!(n−j)!∑i=jn(n−j)!(n−i)!(i−j)!\sum_{j=0}^k\begin{Bmatrix} k\\ j \end{Bmatrix}\frac{n!}{(n-j)!}\sum_{i=j}^n\frac{(n-j)!}{(n-i)!(i-j)!}j=0k{kj}(nj)!n!i=jn(ni)!(ij)!(nj)!

∑j=0k{kj}n!(n−j)!∑i=jn(n−ji−j)\sum_{j=0}^k\begin{Bmatrix} k\\ j \end{Bmatrix}\frac{n!}{(n-j)!}\sum_{i=j}^n\binom{n-j}{i-j}j=0k{kj}(nj)!n!i=jn(ijnj)

化成 222 次幂形式:
∑j=0k{nm}n!(n−j)!∑i=0n−j(n−ji)\sum_{j=0}^k\begin{Bmatrix} n\\ m \end{Bmatrix}\frac{n!}{(n-j)!}\sum_{i=0}^{n-j}\binom{n-j}{i}j=0k{nm}(nj)!n!i=0nj(inj)

∑j=0k{kj}n!(n−j)!×2n−j\sum_{j=0}^k\begin{Bmatrix} k\\ j \end{Bmatrix}\frac{n!}{(n-j)!}\times2^{n-j}j=0k{kj}(nj)!n!×2nj

O(k2)O(k^2)O(k2) 时间复杂度预处理第二类斯特林数即可。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=5002,mod=1e9+7;
ll n,k;
ll S2[N][N],p2[N];
ll qpow(ll x,ll k)
{ll ret=1;while(k){if(k&1)ret=ret*x%mod;x=x*x%mod;k>>=1;}return ret;
}
void init()
{S2[0][0]=1;for(int i=1;i<N;i++)for(int j=1;j<N;j++)S2[i][j]=(S2[i-1][j-1]+j*S2[i-1][j]%mod)%mod;
}
int main()
{scanf("%lld%lld",&n,&k);init();ll ans=0;for(int j=0;j<=min(n,k);j++){ll ret=S2[k][j]*qpow(2,n-j)%mod,mul=1;for(int t=n-j+1;t<=n;t++)ret=ret*t%mod;ans=(ans+ret)%mod;}printf("%lld",ans);return 0;
}

第一类斯特林数

概念

[nm]\begin{bmatrix} n\\ m \end{bmatrix}[nm] 表示,将 nnn 个不同的球摆成 mmm 个环的方案数。两个环相同,当且仅当一个环通过旋转可以变成第二个环。

其递推式的推导:

  • nnn 单开一个环,那么剩下 n−1n-1n1 个球成 m−1m-1m1 个环:[n−1m−1]\begin{bmatrix} n-1\\ m-1 \end{bmatrix}[n1m1]
  • nnn 放进 mmm 个环,在放了的 (n−1)(n-1)(n1) 个球后面都可以放:(n−1)[n−1m](n-1)\begin{bmatrix} n-1\\ m \end{bmatrix}(n1)[n1m]

所以 [nm]=[n−1m−1]+(n−1)[n−1m]\begin{bmatrix} n\\ m \end{bmatrix}=\begin{bmatrix} n-1\\ m-1 \end{bmatrix}+(n-1)\begin{bmatrix} n-1\\ m \end{bmatrix}[nm]=[n1m1]+(n1)[n1m]

特别的,[nm]=[n=0]\begin{bmatrix} n\\ m \end{bmatrix}=[n=0][nm]=[n=0],中括号为艾弗森括号。

洛谷 P4609 FJOI2016 建筑师

题意

小 Z 是一个很有名的建筑师,有一天他接到了一个很奇怪的任务:在数轴上建 nnn 个建筑,每个建筑的高度是 111nnn 之间的一个整数。

小 Z 有很严重的强迫症,他不喜欢有两个建筑的高度相同。另外小 Z 觉得如果从最左边(所有建筑都在右边)看能看到 AAA 个建筑,从最右边(所有建筑都在左边)看能看到 BBB 个建筑,这样的建筑群有着独特的美感。现在,小 Z 想知道满足上述所有条件的建筑方案有多少种?

如果建筑 iii 的左(右)边没有任何建造比它高,则建筑 iii 可以从左(右)边看到。两种方案不同,当且仅当存在某个建筑在两种方案下的高度不同。

1≤n≤50000,1≤A,B≤100,1≤T≤2000001 \leq n \leq 50000, \ 1 \leq A, B \leq 100, \ 1 \leq T \leq 2000001n50000, 1A,B100, 1T200000

思路

中间那个左右都能看见的,高度必然是极值 nnn

除去中间的,左边要看到 a−1a-1a1 个,右边要看到 b−1b-1b1 个。不妨将能看到的和其左/右边比它矮的看成 a−1+b−1=a+b−2a-1+b-1=a+b-2a1+b1=a+b2 个环(反正互换位置之后,尽管某些环的元素种类改变,但是环的个数不改变),就可以用第一类斯特林数的含义,将剩下 n−1n-1n1 和分成 a+b−2a+b-2a+b2 个环,即 [n−1a+b−2]\begin{bmatrix} n-1\\ a+b-2 \end{bmatrix}[n1a+b2]

然后再 a+b−2a+b-2a+b2 个环中选各自最大值 a−1a-1a1 个,成为左边能看见的(排列方式唯一,必然是从矮到高),即 (a+b−2a−1)\dbinom{a+b-2}{a-1}(a1a+b2)

于是答案为 [n−1a+b−2](a+b−2a−1)\begin{bmatrix} n-1\\ a+b-2 \end{bmatrix}\dbinom{a+b-2}{a-1}[n1a+b2](a1a+b2)

预处理第一类斯特林数即可。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=5e4+9,M=202,mod=1e9+7;
ll T;
ll S1[N][M],fac[N],inv[N];
ll qpow(ll x,ll k)
{ll ret=1;while(k){if(k&1)ret=ret*x%mod;x=x*x%mod;k>>=1;}return ret;
}
void init()
{S1[0][0]=1;for(int i=1;i<N;i++)for(int j=1;j<M;j++)S1[i][j]=(S1[i-1][j-1]+(i-1)*S1[i-1][j]%mod)%mod;fac[0]=1;for(int i=1;i<N;i++)fac[i]=fac[i-1]*i%mod;inv[N-1]=qpow(fac[N-1],mod-2);for(int i=N-2;i>=0;i--)inv[i]=inv[i+1]*(i+1)%mod;
}
ll C(ll n,ll m)
{return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
int main()
{scanf("%lld",&T);init();while(T--){ll n,a,b;scanf("%lld%lld%lld",&n,&a,&b);printf("%lld\n",S1[n-1][a+b-2]*C(a+b-2,a-1)%mod);}return 0;
}

无根树的 prufer 序列

概念

prufer 序列将节点数为 nnn 的无根树转化为长为 n−2n-2n2 的序列。其表示期望与根的编号无关——定义为每次选择一个编号最小的叶节点并删除,然后在序列中记录其所连接的节点编号,直到剩下两个节点。

在这里插入图片描述
如上图是一棵有 777 个节点的树的 prufer 序列形成过程。

用 prufer 序列同样可以还原出一棵树来。

求法

求一棵树的 prufer 序列。可以维护每个节点的度数,以节点编号为第一关键字扔进堆里排序,当度为 000 时舍弃这个节点。容易做到 O(nlog⁡n)O(n\log n)O(nlogn)

O(n)O(n)O(n) 的更优秀的算法:“剥叶子”的过程中,每次只会让其父亲节点度数减 111,因此每删除一个叶节点,至多产生一个新叶节点。

因此可以用一个单调指针 pospospos 维护当前度数为 000 的最小结点,pospospos 枚举到了先删 pospospos,然后看 faposfa_{pos}fapos 是否度数变为 000,如果为 000 就顺带删去了;没准是条链,因此可以 while 一路删上去。

用 prufer 还原一棵树亦然。

P6086 【模板】Prufer 序列

思路

如上所述。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=1e5+9;
ll n,m,mod,k;
ll fa[N],siz[N];
ll fz(ll x)
{while(x!=fa[x])x=fa[x]=fa[fa[x]];return x;
}
void join(ll u,ll v)
{ll fu=fz(u),fv=fz(v);if(fu==fv)return;fa[fu]=fv;siz[fv]+=siz[fu];k--;
}
ll qpow(ll x,ll k)
{ll ret=1;while(k){if(k&1)ret=ret*x%mod;x=x*x%mod;k>>=1;}return ret;
}
int main()
{scanf("%lld%lld%lld",&n,&m,&mod);if(mod==1){puts("0");return 0;}k=n;for(int i=1;i<=n;i++)fa[i]=i,siz[i]=1;for(int i=1;i<=m;i++){ll u,v;scanf("%lld%lld",&u,&v);join(u,v);}if(k==1){puts("1");return 0;}ll ans=1;for(int i=1;i<=n;i++)if(i==fz(i))ans=ans*siz[i]%mod;ans=ans*qpow(n,k-2)%mod;printf("%lld",ans);return 0;
}
http://www.lryc.cn/news/590866.html

相关文章:

  • 【AI前沿】英伟达CEO黄仁勋ComputeX演讲2025|Token是AI时代的“新货币”
  • CSDN首发:研究帮平台深度评测——四大AI引擎融合的创作革命
  • 从零开始的云计算生活——第三十三天,关山阻隔,ELK日志分析
  • docker 容器无法使用dns解析域名异常问题排查
  • HCIE - 云计算拿下后的职业选择如何规划?
  • 生成式AI干预下的认知依赖与批判性思维发展:基于ChatGPT辅助写作的纵向追踪
  • HCIE - 云计算方向考什么?一文全解
  • docker--安装--原理
  • Flutter Android打包学习指南
  • 机器学习:数据清洗与预处理 | Python
  • cors跨域资源共享
  • 2025年Java后端秋招面试的高频八股文+场景题
  • Linux C 进程基本操作
  • 【Elasticsearch】Elasticsearch 快照恢复 API 参数详解
  • Git 多人协作实战:从基础操作到分支管理全流程记录
  • 关于el-table异步获取数据渲染动态列数据赋值列数据渲染时title高度异常闪过问题
  • vue3+ts+elementui-表格根据相同值合并
  • Linux之Zabbix分布式监控篇(二)
  • 算法竞赛备赛——【图论】求最短路径——Floyd算法
  • 【华为机试】122. 买卖股票的最佳时机 II
  • React 学习(4)
  • 研发知识系统选型实战:从 Notion 到 Gitee Wiki 的迭代经验
  • STM32 DMA通信详解
  • 求解偏微分方程的傅里叶积分解
  • ThreadLocal使用详解-从源码层面分析
  • Python 网络爬虫 —— requests 库和网页源代码
  • 智能体开发工具链全景图:IDE、调试器与监控平台
  • Fair-code介绍(Fair code)(一套新型软件模型:旨在“开源”“商业可持续性”中找到平衡)
  • Windows 11清理C盘方法大全:磁盘清理/禁用休眠/系统还原点/优化大师使用教程
  • Android默认背光亮度配置说明