📜  生成函数(1)

📅  最后修改于: 2023-12-03 15:11:13.621000             🧑  作者: Mango

生成函数

什么是生成函数

生成函数是组合数学中的一种方法,可以用于解决组合计数问题。它将序列(通常是组合数序列)表示为一个形式幂级数的系数。

形式幂级数

形式幂级数是指一个无穷个变量构成的级数,我们通常用 $F(x)$ 这样的形式表示,其中 $x$ 代表着变量。例如:

$$ F(x) = \sum_{n \geq 0} a_n x^n $$

在生成函数的应用中,$a_n$ 通常是某个图形问题的解,而 $x$ 则表示某种状态(如色彩、位置、大小等)。

常见的生成函数
普通生成函数

有种生成函数称为普通生成函数,它的定义如下:

$$ F(x) = \sum_{n \geq 0} a_n x^n $$

其中 $a_n$ 代表着组合计数问题的答案。

指数型生成函数

另一种生成函数的形式如下:

$$ F(x) = \sum_{k \geq 0} \frac{a_k}{k!} x^k $$

我们称其为指数型生成函数。这种生成函数通常用于统计排列,因为排列问题与阶乘 $n!$ 相关。

阶乘型生成函数

一些组合问题与阶乘相关,因此我们还有另一种生成函数,称之为阶乘型生成函数。它的定义如下:

$$ F(x) = \sum_{n \geq 0} \frac{a_n}{n!} x^n $$

其中 $a_n$ 是问题的解。这种生成函数在组合计数中是最常见的。

生成函数的应用

生成函数可以应用于各种组合问题,例如:

  1. 排列问题
  2. 组合问题
  3. 多重组合问题
  4. 二项式系数问题
  5. 分割问题
  6. 火车进出站问题
实现

生成函数的实现通常涉及到多项式运算,因此需要对多项式的加、减、乘、求导等基本操作有一定的掌握。C++ 中可以使用 STL 库的 valarray 类来实现。以下是一个示例代码:

#include <bits/stdc++.h>
using namespace std;

typedef valarray<double> Poly;

Poly operator+(const Poly &a, const Poly &b) {
    Poly res(max(a.size(), b.size()));
    for (size_t i = 0; i < res.size(); ++i) {
        if (i < a.size()) res[i] += a[i];
        if (i < b.size()) res[i] += b[i];
    }
    return res;
}

Poly operator-(const Poly &a, const Poly &b) {
    Poly res(max(a.size(), b.size()));
    for (size_t i = 0; i < res.size(); ++i) {
        if (i < a.size()) res[i] += a[i];
        if (i < b.size()) res[i] -= b[i];
    }
    return res;
}

Poly operator*(const Poly &a, const Poly &b) {
    Poly res(a.size() + b.size() - 1);
    for (size_t i = 0; i < a.size(); ++i)
        for (size_t j = 0; j < b.size(); ++j)
            res[i + j] += a[i] * b[j];
    return res;
}

Poly operator&(const Poly &a, const Poly &b) {
    Poly res(a.size() + b.size() - 1);
    for (size_t i = 0; i < a.size(); ++i)
        for (size_t j = 0; j < b.size(); ++j)
            res[i + j] += a[i] * b[j];
    return res;
}

void D(Poly &a) { // 求导数
    size_t n = a.size();
    for (size_t i = 1; i < n; ++i) a[i - 1] = a[i] * i;
    if (n) a[n - 1] = 0;
}

void I(Poly &a) { // 积分
    size_t n = a.size();
    for (int i = n - 1; i >= 1; --i) a[i] = a[i - 1] / i;
    if (n) a[0] = 0;
}

void get_ord(int &m) { // 获取m值
    printf("请输入 m 值:\n");
    scanf("%d", &m);
}

void input(Poly &a, Poly &b) { // 输入两个多项式
    int n, m;
    printf("请输入多项式 A 的次数:\n");
    scanf("%d", &n);
    a.resize(n + 1);
    printf("请依次输入 A 的系数:\n");
    for (int i = 0; i <= n; ++i) scanf("%lf", &a[i]);
    printf("请输入多项式 B 的次数:\n");
    scanf("%d", &m);
    b.resize(m + 1);
    printf("请依次输入 B 的系数:\n");
    for (int i = 0; i <= m; ++i) scanf("%lf", &b[i]);
}

void solve(Poly &a, Poly &b) { // 求解
    int m;
    get_ord(m);
    a.resize(m + 1);
    D(a);
    b.resize(m + 1);
    I(b);
    Poly ans = (a & b);
    for (int i = 0; i <= m; ++i) printf("%.3lf ", ans[i]);
}

int main() {
    Poly A, B;
    input(A, B);
    solve(A, B);
    return 0;
}

生成函数的实现还可以涉及到 FFT、NTT 等高级算法,这里不再一一列出。