生成函数
一、生成函数基础概念
1.1 普通生成函数(OGF)
普通生成函数的形式为:
\[G(x) = a_0 + a_1x + a_2x^2 + \dots + a_nx^n
\]
适用于组合计数问题,如背包问题、整数划分等。
1.2 指数生成函数(EGF)
指数生成函数的形式为:
\[G(x) = a_0 + a_1\frac{x}{1!} + a_2\frac{x^2}{2!} + \dots
\]
适用于排列计数问题,如带标号对象的组合。
二、经典应用场景
2.1 递推关系求解
例题1:斐波那契数列通项公式
题目链接:斐波那契数列 - 洛谷 P1962
问题描述:
已知斐波那契数列的递推式:
\[f(0) = 0, \quad f(1) = 1 \\
f(n) = f(n-1) + f(n-2) \quad (n \geq 2)
\]
求斐波那契数列的通项公式。
生成函数解法:
- 设生成函数:\[F(x) = \sum_{n=0}^{\infty} f(n)x^n \]
- 根据递推关系建立方程:\[F(x) = x + xF(x) + x^2F(x) \]
- 解得生成函数的闭合形式:\[F(x) = \frac{x}{1 - x - x^2} \]
- 对生成函数进行部分分式分解:\[F(x) = \frac{1}{\sqrt{5}} \left( \frac{1}{1 - \phi x} - \frac{1}{1 - \psi x} \right) \]其中,\(\phi = \frac{1 + \sqrt{5}}{2}\),\(\psi = \frac{1 - \sqrt{5}}{2}\)。
- 展开生成函数,得到通项公式:\[f(n) = \frac{\phi^n - \psi^n}{\sqrt{5}} \]
C++代码实现:
#include <iostream>
#include <cmath>
using namespace std;
double fib(int n) {
double phi = (1 + sqrt(5)) / 2;
double psi = (1 - sqrt(5)) / 2;
return (pow(phi, n) - pow(psi, n)) / sqrt(5);
}
int main() {
int n;
cin >> n;
cout << "Fibonacci number F(" << n << ") = " << fib(n) << endl;
return 0;
}
2.2 组合计数问题
例题2:多重集组合数
题目链接:多重集组合数 - 洛谷 P1025
问题描述:
有三种物品,分别有无限个、至少取2个、最多取3个,求取5个物品的方案数。
生成函数解法:
- 构建生成函数:\[G(x) = (1 + x + x^2 + \dots)(x^2 + x^3 + \dots)(1 + x + x^2 + x^3) \]
- 化简生成函数:\[G(x) = \frac{1}{1 - x} \cdot \frac{x^2}{1 - x} \cdot \frac{1 - x^4}{1 - x} \]
- 合并得到:\[G(x) = \frac{x^2(1 - x^4)}{(1 - x)^3} \]
- 展开 \((1 - x)^{-3}\) 使用广义二项式定理:\[(1 - x)^{-3} = \sum_{n=0}^{\infty} \binom{n + 2}{2} x^n \]
- 计算 \(x^5\) 的系数:\[\binom{5 + 2}{2} - \binom{1 + 2}{2} = 21 - 3 = 18 \]
C++代码实现:
#include <iostream>
using namespace std;
int main() {
int n = 5;
int result = 0;
for (int a = 0; a <= n; a++) { // 第一种物品
for (int b = 2; b <= n; b++) { // 第二种物品
for (int c = 0; c <= 3; c++) { // 第三种物品
if (a + b + c == n) {
result++;
}
}
}
}
cout << "Number of ways: " << result << endl;
return 0;
}
三、例题
例题3:货币系统问题
题目链接:货币系统 - 洛谷 P5020
问题描述:
给定面值分别为3元、5元、7元的硬币,求组成100元的方案数。
生成函数解法:
- 构造生成函数:\[G(x) = (1 + x^3 + x^6 + \dots)(1 + x^5 + x^{10} + \dots)(1 + x^7 + x^{14} + \dots) \]
- 化简生成函数:\[G(x) = \frac{1}{(1 - x^3)(1 - x^5)(1 - x^7)} \]
- 需要求 \(x^{100}\) 的系数。
优化计算:
使用动态规划结合生成函数思想:
#include <iostream>
using namespace std;
const int MOD = 1e9 + 7;
int main() {
int target = 100;
int coins[] = {3, 5, 7};
int dp[101] = {0};
dp[0] = 1;
for (int coin : coins) {
for (int i = coin; i <= target; i++) {
dp[i] = (dp[i] + dp[i - coin]) % MOD;
}
}
cout << "Number of ways to make 100: " << dp[100] << endl;
return 0;
}
四、练习题
以下是一些洛谷上的生成函数相关练习题
-
[P4721] 分治FFT
题目链接:P4721
标签:生成函数、FFT、分治 -
[P4841] 城市规划
题目链接:P4841
标签:生成函数、多项式、组合数学 -
[P5162] WD与积木
题目链接:P5162
标签:生成函数、动态规划、多项式 -
[P5748] 集合划分计数
题目链接:P5748
标签:生成函数、多项式、组合数学

浙公网安备 33010602011771号