[模板] 常系数线性递推

常系数线性递推

给定向量 \(A_0 = (a_1, a_2, \dotsc, a_k)\), 和向量 \(H = (h_1, h_2, \dotsc, h_k)\), 同时

\[
a_n = \sum_{i=1}^k a_{n-i} h_i
\]

求 \(a_n\).

算法

我们只需求出 \(A_n = (a_n, a_{n+1}, \dotsc, a_{n+k-1})\) 即可.

设 \(f(\lambda)\) 表示转移方程的特征多项式, 有

\[
f(\lambda) = \lambda^k - \sum_{i=0}^{k-1} h_{k-i} \lambda^i
\]

设 \(g(\lambda) \equiv \lambda^{n-1} \pmod{f(\lambda)}\), 那么有

\[
a_n = \sum_{i=0}^{k-1} g_i a_{i+1}
\]

求 \(g(\lambda)\) 如果直接取模则复杂度为 \(O(k^2\log n)\), 多项式取模则为 \(O(k\log k \log n)\).

代码

bzoj4161: Shlw loves matrixI

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define rep(i,l,r) for(register int i=(l);i<=(r);++i)
#define repdo(i,l,r) for(register int i=(l);i>=(r);--i)
#define il inline
typedef long long ll;
typedef double db;

//---------------------------------------
const int nsz=4050;
const ll nmod=1e9+7;
int n,k;

ll v1[nsz],v2[nsz];//a_n = \sum_{i=1}^k v1[i]v2[n-i]
ll f[nsz],g[nsz],h[nsz],c[nsz];

ll qp(ll a,ll b){
    ll res=0;
    for(;b;b>>=1,a=a*a%nmod)if(b%1)res=res*a%nmod;
    return res;
}

void mul(ll *a,ll *b,ll *res){//res=a*b%f
    rep(i,0,k*2)c[i]=0;
    rep(i,0,k-1)rep(j,0,k-1)c[i+j]=(c[i+j]+a[i]*b[j])%nmod;
    repdo(i,k*2-2,k){
        if(c[i]){
            rep(j,0,k){
                c[i-k+j]=(c[i-k+j]-c[i]*f[j])%nmod;
            }
        }
    }
    rep(i,0,k-1)res[i]=c[i];
}

void qp(ll *a,ll b,ll *c){
    c[0]=1;
    for(;b;b>>=1,mul(a,a,a))
    if(b&1)
    mul(c,a,c);
}

ll getrecurrence(){
    if(n<=k)return v2[n]%nmod;
    if(k==1){return qp(v1[1],n)*v2[0]%nmod;}
    ++n;
    rep(i,0,k-1)f[i]=-v1[k-i];
    f[k]=1;
    g[1]=1;
    qp(g,n-1,h);
    ll res=0;
    rep(i,0,k-1){
        res=(res+h[i]*v2[i])%nmod;
    }
    return res;
} 

int main(){
    ios::sync_with_stdio(0),cin.tie(0);
    cin>>n>>k;
    rep(i,1,k)cin>>v1[i];
    rep(i,0,k-1)cin>>v2[i];
    cout<<(getrecurrence()+nmod)%nmod<<'\n';
    return 0;
}

原文地址:https://www.cnblogs.com/ubospica/p/11066886.html

时间: 2024-10-09 13:35:59

[模板] 常系数线性递推的相关文章

常系数线性递推的第n项及前n项和 (Fibonacci数列,矩阵)

(一)Fibonacci数列f[n]=f[n-1]+f[n-2],f[1]=f[2]=1的第n项的快速求法(不考虑高精度). 解法: 考虑1×2的矩阵[f[n-2],f[n-1]].根据fibonacci数列的递推关系,我们希望通过乘以一个2×2的矩阵,得到矩阵[f[n-1],f[n]]=[f[n-1],f[n-1]+f[n-2]] 很容易构造出这个2×2矩阵A,即: 0 1 1 1 所以,有[f[1],f[2]]×A=[f[2],f[3]] 又因为矩阵乘法满足结合律,故有: [f[1],f[2

Codeforces 1106F Lunar New Year and a Recursive Sequence (数学、线性代数、线性递推、数论、BSGS、扩展欧几里得算法)

哎呀大水题..我写了一个多小时..好没救啊.. 数论板子X合一? 注意: 本文中变量名称区分大小写. 题意: 给一个\(n\)阶递推序列\(f_k=\prod^{n}_{i=1} f_{k-i}b_i\mod P\)其中\(P=998244353\), 输入\(b_1,b_2,...,b_n\)以及已知\(f_1,f_2,...,f_{n-1}=1\), 再给定一个数\(m\)和第\(m\)项的值\(f_m\), 求出一个合法的\(f_n\)值使得按照这个值递推出来的序列满足第\(m\)项的值为

杜教BM递推板子

Berlekamp-Massey 算法用于求解常系数线性递推式 #include<bits/stdc++.h> typedef std::vector<int> VI; typedef long long ll; typedef std::pair<int, int> PII; const ll mod = 1000000007; ll powmod(ll a, ll b) { ll res = 1; a %= mod; assert(b >= 0); for(;

POJ3070 Fibonacci(矩阵快速幂加速递推)【模板题】

题目链接:传送门 题目大意: 求斐波那契数列第n项F(n). (F(0) = 0, F(1) = 1, 0 ≤ n ≤ 109) 思路: 用矩阵乘法加速递推. 算法竞赛进阶指南的模板: #include <iostream> #include <cstring> using namespace std; const int MOD = 10000; void mul(int f[2], int base[2][2]) { int c[2]; memset(c, 0, sizeof

LG4723 【模板】常系数齐次线性递推

P4723 [模板]常系数齐次线性递推 题目描述 求一个满足$k$阶齐次线性递推数列${a_i}$的第$n$项. 即:$a_n=\sum\limits_{i=1}^{k}f_i \times a_{n-i}$ 输入输出格式 输入格式: 第一行两个数$n$,$k$,如题面所述. 第二行$k$个数,表示$f_1 \ f_2 \ \cdots \ f_k$ 第三行$k$个数,表示$a_0 \ a_1 \ \cdots \ a_{k-1}$ 输出格式: 一个数,表示 $a_n \% 998244353$

[LGOJ]P1939【模板】矩阵加速(数列)[矩阵加速递推]

题面 矩阵加速递推的原理: 首先你得会矩阵乘法与快速幂. 以斐波拉契数列为例, 要从矩阵A \[ \begin{bmatrix} f[n-1] & f[n]  \end{bmatrix} \] 得到矩阵B \[ \begin{bmatrix} f[n] & f[n+1]  \end{bmatrix} \] 显然可以\[\begin{bmatrix} f[n-1] & f[n] \end{bmatrix}\times \begin{bmatrix}  0 & 1\\ 1 &a

hiho 1143 矩阵快速幂 求递推式

题目链接: hihocoder 1143 思路见题目上 快速幂模板: // m^n % k int quickpow(int m,int n,int k) { int b = 1; while (n > 0) { if (n & 1) b = (b*m)%k; n = n >> 1 ; m = (m*m)%k; } return b; } 题解: #include<iostream> #include<cstdio> #include<cstring

hdu--1028--dp||递推||母函数

这题开始的时候犯了和做--调皮的小明的时候 一样的错误 去dfs了 果断TLE啊 然后想起来 就dp去做... 还有一些别的做法 有人用递推 或者 母函数做的 其实递推的话 还是和dp有点像的 还有一种 记忆化搜索的方法 太流弊了 我把它都贴出来好了 1 /* 2 #include <iostream> 3 #include <cstring> 4 using namespace std; 5 6 int n , cnt; 7 void dfs( int pos , int sum

一道简单的递推题(快速幂+矩阵乘法优化+滚动数组)

问题 F: 一道简单的递推题 时间限制: 1 Sec  内存限制: 128 MB提交: 546  解决: 48[提交][状态][讨论版] 题目描述 存在如下递推式: F(n+1)=A1*F(n)+A2*F(n-1)+...+An*F(1) 求第K项的值对1000000007取模的结果 输入 单组测试数据 第一行输入两个整数 n , k (1<=n<=100,n<k<=10000000000) 第二行输入 n 个整数 F(1)   F(2)   ...   F(n) 第三行输入 n