8.13.9 ACM-ICPC 多项式与生成函数 常系数齐次线性递推

8.13.9 ACM-ICPC 多项式与生成函数: 常系数齐次线性递推

本节介绍常系数齐次线性递推的相关内容。具体包括以下几个部分:

  • 齐次线性递推的定义
  • 齐次线性递推方程的求解方法
  • 特征多项式及其作用
  • 递推关系的具体例子
  • 代码实现与算法优化

齐次线性递推的定义

常系数齐次线性递推是指一个递推关系,其中每一项由前几项的线性组合表示,且组合系数是常数。其一般形式为:

an=c1an−1+c2an−2+⋯+ckan−ka_n = c_1 a_{n-1} + c_2 a_{n-2} + \cdots + c_k a_{n-k}an​=c1​an−1​+c2​an−2​+⋯+ck​an−k​

其中,c1,c2,…,ckc_1, c_2, \ldots, c_kc1​,c2​,…,ck​ 为常系数,ana_nan​ 为第 nnn 项。

求解方法

解决常系数齐次线性递推问题的关键在于找到通项公式。通常通过以下步骤实现:

  1. 构造特征多项式:设递推关系为 an=c1an−1+c2an−2+⋯+ckan−ka_n = c_1 a_{n-1} + c_2 a_{n-2} + \cdots + c_k a_{n-k}an​=c1​an−1​+c2​an−2​+⋯+ck​an−k​,其对应的特征多项式为:

    P(x)=xk−c1xk−1−c2xk−2−⋯−ckP(x) = x^k - c_1 x^{k-1} - c_2 x^{k-2} - \cdots - c_kP(x)=xk−c1​xk−1−c2​xk−2−⋯−ck​

  2. 求解特征方程:求特征多项式 P(x)=0P(x) = 0P(x)=0 的根。设根为 r1,r2,…,rmr_1, r_2, \ldots, r_mr1​,r2​,…,rm​,每个根的重数分别为 α1,α2,…,αm\alpha_1, \alpha_2, \ldots, \alpha_mα1​,α2​,…,αm​。

  3. 构造通项公式:根据特征方程的根,构造递推关系的通项公式。对于单根 rir_iri​,通项公式中对应的部分为 AirinA_i r_i^nAi​rin​;对于重根 rir_iri​(重数为 αi\alpha_iαi​),通项公式中对应的部分为 (Bi0+Bi1n+Bi2n2+⋯+Bi(αi−1)nαi−1)rin(B_{i0} + B_{i1} n + B_{i2} n^2 + \cdots + B_{i(\alpha_i-1)} n^{\alpha_i-1}) r_i^n(Bi0​+Bi1​n+Bi2​n2+⋯+Bi(αi​−1)​nαi​−1)rin​。

特征多项式及其作用

特征多项式在求解常系数齐次线性递推中起到关键作用。通过特征多项式的根,可以将递推关系转化为求解特征方程的问题,从而利用代数方法求得递推关系的通项公式。

递推关系的具体例子

例子1:斐波那契数列

斐波那契数列是常系数齐次线性递推的一个经典例子,其递推关系为:

对应的特征多项式为:

P(x)=x2−x−1P(x) = x^2 - x - 1P(x)=x2−x−1

求解特征方程 x2−x−1=0x^2 - x - 1 = 0x2−x−1=0,得根为:

r1=1+52,r2=1−52r_1 = \frac{1 + \sqrt{5}}{2}, \quad r_2 = \frac{1 - \sqrt{5}}{2}r1​=21+5​​,r2​=21−5​​

因此,斐波那契数列的通项公式为:

例子2:线性递推

考虑递推关系:

对应的特征多项式为:

P(x)=x2−2x+1P(x) = x^2 - 2x + 1P(x)=x2−2x+1

求解特征方程 x2−2x+1=0x^2 - 2x + 1 = 0x2−2x+1=0,得根为:

r=1r = 1r=1

由于是重根,通项公式为:

代码实现与算法优化

为了在程序中高效实现常系数齐次线性递推,可以使用矩阵快速幂的方法。以下是一个示例代码,展示了如何使用矩阵快速幂求解斐波那契数列:

#include <iostream>
#include <vector>

using namespace std;

typedef vector<vector<long long>> matrix;
const long long MOD = 1e9 + 7;

matrix multiply(const matrix &A, const matrix &B) {
    matrix C(2, vector<long long>(2));
    for (int i = 0; i < 2; ++i)
        for (int j = 0; j < 2; ++j)
            for (int k = 0; k < 2; ++k)
                C[i][j] = (C[i][j] + A[i][k] * B[k][j]) % MOD;
    return C;
}

matrix power(matrix A, long long n) {
    matrix result = {{1, 0}, {0, 1}};
    while (n > 0) {
        if (n % 2 == 1)
            result = multiply(result, A);
        A = multiply(A, A);
        n /= 2;
    }
    return result;
}

long long fibonacci(long long n) {
    if (n == 0) return 0;
    matrix F = {{1, 1}, {1, 0}};
    matrix result = power(F, n - 1);
    return result[0][0];
}

int main() {
    long long n;
    cout << "Enter n: ";
    cin >> n;
    cout << "Fibonacci(" << n << ") = " << fibonacci(n) << endl;
    return 0;
}

以上代码利用矩阵快速幂算法,高效计算了斐波那契数列的第 nnn 项,时间复杂度为 O(log⁡n)O(\log n)O(logn)。

通过了解和掌握常系数齐次线性递推的求解方法和代码实现,可以有效解决许多递推关系问题,从而在竞赛中取得更好的成绩。


问题

前置知识
  • 多项式取模
做法

那么就可以通过多次对 A(x)A(x)A(x) 加上 xnG(x)x^n G(x)xnG(x) 的倍数来降低 A(x)A(x)A(x) 的次数。

也就是求 F(A(x)mod  G(x))F(A(x) \mod G(x))F(A(x)modG(x)) 其中 A(x)mod  G(x)A(x) \mod G(x)A(x)modG(x) 的次数不超过 k−1k-1k−1,而 f0..k−1f_{0..k-1}f0..k−1​ 已经给出了,就可以计算了。

问题转化成了快速地求 xnmod  G(x)x^n \mod G(x)xnmodG(x),只要将普通快速幂中的乘法与取模换成多项式乘法与多项式取模,就可以在 O(klog⁡klog⁡n)O(k \log k \log n)O(klogklogn) 的时间复杂度内解决这个问题了。

矩阵的解释

该算法由 Fiduccia 在 1985 年提出,对于 t≥0t \geq 0t≥0 我们定义列向量 vtv_tvt​ 为

那么不难发现

因为 vt+kv_{t+k}vt+k​ 中每一行都满足这个递推关系,我们将 vt+kv_{t+k}vt+k​ 描述为一个线性组合如

发现若能将两边的 vtv_tvt​ 消去后得到多项式

假设我们要求 MnM^nMn 可以构造多项式 f(x)=xnf(x) = x^nf(x)=xn 那么 f(M)=Mnf(M) = M^nf(M)=Mn,而现在我们可将 f(x)f(x)f(x) 写成 f(x)=Q(x)Γ(x)+R(x)f(x) = Q(x) \Gamma(x) + R(x)f(x)=Q(x)Γ(x)+R(x),而其中零矩阵是没有贡献的,那么 f(M)=R(M)f(M) = R(M)f(M)=R(M)。

但是注意矩阵乘法不满足消去律,此处我们定义矩阵 MMM 的特征多项式为 Γ(x)=det⁡(xI−M)\Gamma(x) = \det(xI - M)Γ(x)=det(xI−M),其中 III 为一个 k×kk \times kk×k 的单位矩阵。Cayley–Hamilton 定理指出 Γ(M)=O\Gamma(M) = OΓ(M)=O,我们观察 MMM 的形式较为特殊,为下 Hessenberg 矩阵,其特征多项式比起一般矩阵更容易计算。

我们从右下角的 2×22 \times 22×2 矩阵开始计算特征多项式

右下角 3×33 \times 33×3 矩阵按照第一行的余子式展开有

观察并归纳有

至此我们可以使用上面的结论。令 g(x)=f(x)mod  Γ(x)g(x) = f(x) \mod{\Gamma(x)}g(x)=f(x)modΓ(x) 有 g(M)=Mng(M) = M^ng(M)=Mn,而 deg⁡(g(x))<k\deg(g(x)) < kdeg(g(x))<k 显然,令

那么

我们关注 v0,v1,…,vk−1v_0, v_1, \dots, v_{k-1}v0​,v1​,…,vk−1​ 的第一行就是 f0,f1,…,fk−1f_0, f_1, \dots, f_{k-1}f0​,f1​,…,fk−1​ 已知,那么 fnf_nfn​ 可在 O(k)O(k)O(k) 时间简单得到。求出 g(x)g(x)g(x) 则可用快速幂和多项式取模与上述解释是一样的。该算法常数较大,使用生成函数可以得到一个常数更小的算法。

  • 30
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夏驰和徐策

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值