====== 常系数齐次线性递推 ====== ===== 算法思想 ===== 求一个满足 $k$ 阶齐次线性递推数列 $a_{i}$ 的第 $n$ 项,即: $a_{n}=\sum_{i=1}^{k} f_{i}×a_{n-i}$ ,求 $a_{n}$ 。 其中 $n≤10^{9},k≤32000,|f_{i}|,|a_{0},…,a_{k-1}|≤10^{9}$ 解法是求用快速幂求 $x^{n}$ 对特征多项式 $p$ 取模的结果。 比如求斐波那契数列的第五项 $fib_{5}$ ,于是我们相当于 $0x^{0}+0x^{1}+…+1x^{5}$。 我们先把 $x^{5}$ 的系数减一,再把 $x^{4}$ 和 $x^{3}$ 系数都加一,从而变成 $0x^{0}+0x^{1}+…+1x^{3}+1x^{4}+0x^{5}$ 。相当于对于 $x^{2}-x-1$ 取模。剩下依次类推。 于是原题相当于求出多项式 $x^{n}$ 对多项式 $x_{k}-p_{1}x_{k-1}-p_{2}x_{k-1}-…-p_{k}$ 取模。 ===== 算法实现 ===== #include #define int long long using namespace std; const int N=2000006,GG=3,GI=332748118,mod=998244353; inline void read(int &X){ X = 0; int w=0; char ch=0; while(!isdigit(ch)) {w|=ch=='-';ch=getchar();} while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); if (w) X = -X; } namespace my_f { int qpow(int a,int b,int m=mod) { int r=1; while(b) { if (b&1) r=r*a%m; a=a*a%m,b>>=1; } return r; } int pgg[30],pgi[30]; void init() { for(register int i=0; i<=23; i++) { pgg[i]=qpow(GG,(mod-1)>>i); pgi[i]=qpow(GI,(mod-1)>>i); } } #define ad(x,y) ((x)+(y)>mod?(x)+(y)-mod:(x)+(y)) #define dc(x,y) ((x)-(y)<0?(x)-(y)+mod:(x)-(y)) namespace poly { int w[N],r[N]; void NTT(int f[N],int lim,int type) { for(register int i=0; i>1]>>1)|((i&1)?len:0)); NTT(a,lim,1); NTT(b,lim,1); for(register int i=0; i>1]>>1)|((i&1)?len:0)); NTT(a,lim,1); NTT(b,lim,1); for(register int i=0; i>1]>>1)|((i&1)?len:0)); NTT(b,lim,1); NTT(Q,lim,1); for(register int i=0; i>=1; } for(int i=0; i