CH定理与线性递推
才发觉自己数学差的要死,而且脑子有点浑浑噩噩的,学了一个晚上才学会
如果说的有什么不对的可以在下面嘲讽曲明
以下无特殊说明时,默认方阵定义在实数域上,用\(|A|\)表示\(A\)的行列式
特征值与特征向量
对于一个\(n\)阶方阵\(A\),如果存在某个列向量\(v\)和\(\lambda\in R\),使得
Av=\lambda v
\end{aligned}
\]
则我们称\(v\)为矩阵\(A\)的特征向量,\(\lambda\)为对应的特征值
不难发现上面的等式可以写成
(\lambda E-A)v=0
\end{aligned}
\]
根据线代的基本芝士,可以得知
一,如果\(A\)满秩,则\(A\)有\(n\)组线性无关的特征向量
二,如果\(|\lambda E-A|=0\),则存在\(v\)使等式成立,否则不存在
Cayley-Hamilton定理
假设\(A\)满秩。记\(A\)的特征多项式为\(f(\lambda)=|\lambda E-A|\),其中\(\lambda\)代表未知数。通过暴力展开行列式易知\(f\)是关于\(\lambda\)的一个\(n\)次多项式,设其为\(f(\lambda)=\lambda^n+\sum_{i=1}^na_i\lambda^{n-i}\),则\(f(A)=A^n+\sum_{i=1}^na_iA^{n-i}=0\)
可以跳过证明直接看下面了
对于\(f(\lambda)\),它的\(n\)个根为\(\lambda_k\),其中\(\lambda_{k}\)表示\(A\)的第\(k\)个特征值,所以不考虑常数倍时,它可以写成
f(\lambda)=\prod_{k}(\lambda_{k}-\lambda)
\end{aligned}
\]
所以我们需要证明下列等式恒成立
\prod_{k}(\lambda_{k} E-A)=0
\end{aligned}
\]
直接证明它为\(0\)很难,我们可以考虑证明任意向量乘上它为\(0\)
因为它的\(n\)组特征向量线性无关,所以任意向量都可以被这\(n\)组特征向量表示,那么只要证明任意特征向量乘上它为\(0\)即可
首先,可以证明它满足交换律
(aE-A)(bE-A)=abE^2-aEA-bEA+A^2=(bE-A)(aE-A)
\end{aligned}
\]
那么就可以把里面的给提出来
v_i\prod_{k}(\lambda_{k} E-A)=v_i(\lambda_{i} E-A)\prod_{k\neq i}(\lambda_{k} E-A)=0
\end{aligned}
\]
就没了
线性递推
先考虑求出\(f(\lambda)\),对于\(|\lambda E-A|\),我们写出这个矩阵,并对第一列展开,可得\(f(\lambda)=\lambda^n-\sum_{i=1}^na_i\lambda^{n-i}\),于是我们可以得到\(f(A)\)的系数了
递推关系为
h_i=\sum_{j=1}^na_jh_{i-j}
\end{aligned}
\]
\(h_{0,...,n-1}\)已给出,求\(h_k\)
我们记初始向量为\(S\),其中\(S_i=h_i\),转移矩阵为\(A\),以及\(B(x)=f(A)\),那么最终要求的就是\((S\times A^n)_0\)
我们记\(C(A)\equiv A^n\pmod{B(A)}\),由于\(B=0\),所以\(C(A)=A^{n}\)
注意这里模一个零多项式不会有问题,因为取模相等于减去若干个\(B(A)\)
而且由于\(C(A)\)是模\(B(A)\)后的多项式,所以\(C(A)\)的次数小于\(n\),即\(C(A)\)可以写成\(\sum_{i=0}^{n-1}c_iA^i\)
那么最终要求的柿子就可以写成
(S\times A^n)_0
&=(S\times \sum_{i=0}^{n-1}c_iA^i)_0\\
&=\sum_{i=0}^{n-1}c_i(S\times A^i)_0\\
\end{aligned}
\]
这里\(S\times A^i\),事实上就是\(S_i\),所以最终的答案就是
h_n=\sum_{i=0}^{n-1}c_ih_i
\end{aligned}
\]
求\(C\)的话,用多项式快速幂+取模即可,如果都是暴力实现的话复杂度是\(O(n^2\log k)\),如果用\(NTT\)可以优化到\(O(n\log n \log k)\)
bzoj4161,暴力
//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int P=1e9+7;
inline void upd(R int &x,R int y){(x+=y)>=P?x-=P:0;}
inline int inc(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
R int res=1;
for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
return res;
}
const int N=2005;
typedef vector<int> poly;
int a[N],b[N],L,n,res;poly c,d,md;
poly operator %(R poly a,R poly b){
R int n=a.size(),m=b.size(),t,iv=inc(0,P-ksm(b[m-1],P-2));
fd(i,n-1,m-1)if(a[i]){
t=mul(a[i],iv);
fp(j,0,m-1)upd(a[i-j],mul(t,b[m-1-j]));
}
while(!a.empty()&&!a.back())a.pop_back();
return a;
}
poly operator *(R poly a,R poly b){
R int n=a.size(),m=b.size();poly c(n+m-1);
fp(i,0,n-1)fp(j,0,m-1)upd(c[i+j],mul(a[i],b[j]));
return c%md;
}
int main(){
// freopen("testdata.in","r",stdin);
scanf("%d%d",&L,&n);
fp(i,1,n)scanf("%d",&a[i]),upd(a[i],P);
fp(i,0,n-1)scanf("%d",&b[i]),upd(b[i],P);
md.resize(n+1);md[n]=1;fp(i,0,n-1)md[i]=inc(0,P-a[n-i]);
c.resize(1),d.resize(2),c[0]=1,d[1]=1;
for(;L;L>>=1,d=d*d)if(L&1)c=c*d;
res=0;
fp(i,0,n-1)upd(res,mul(c[i],b[i]));
printf("%d\n",res);
return 0;
}
洛谷4723 NTT优化
常数极大,极大
//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int P=998244353;
inline void upd(R int &x,R int y){(x+=y)>=P?x-=P:0;}
inline int inc(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
R int res=1;
for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
return res;
}
const int N=(1<<17)+5;
int rt[2][N],r[18][N],inv[18],lg[N],md[N],A[N],B[N],a[N],b[N],lim,d,n,K;
void init(){
fp(d,1,16){
fp(i,1,(1<<d)-1)r[d][i]=(r[d][i>>1]>>1)|((i&1)<<(d-1));
inv[d]=ksm(1<<d,P-2),lg[1<<d]=d;
}
for(R int t=(P-1)>>1,i=1,x,y;i<65536;t>>=1,i<<=1){
x=ksm(3,t),y=ksm(332748118,t),rt[0][i]=rt[1][i]=1;
fp(k,1,i-1){
rt[0][i+k]=mul(rt[0][i+k-1],x);
rt[1][i+k]=mul(rt[1][i+k-1],y);
}
}
}
void NTT(int *A,int ty){
int t;
fp(i,0,lim-1)if(i<r[d][i])swap(A[i],A[r[d][i]]);
for(R int mid=1;mid<lim;mid<<=1)
for(R int j=0;j<lim;j+=(mid<<1))
fp(k,0,mid-1){
A[j+k+mid]=inc(A[j+k],P-(t=mul(A[j+k+mid],rt[ty][mid+k])));
upd(A[j+k],t);
}
if(!ty){
t=inv[d];
fp(i,0,lim-1)A[i]=mul(A[i],t);
}
}
void Inv(int *a,int *b,int len){
if(len==1)return b[0]=ksm(a[0],P-2),void();
Inv(a,b,len>>1);
static int A[N],B[N];lim=(len<<1),d=lg[lim];
fp(i,0,len-1)A[i]=a[i],B[i]=b[i];
fp(i,len,lim-1)A[i]=B[i]=0;
NTT(A,1),NTT(B,1);
fp(i,0,lim-1)A[i]=mul(A[i],mul(B[i],B[i]));
NTT(A,0);
fp(i,0,len-1)upd(b[i],inc(b[i],P-A[i]));
fp(i,len,lim-1)b[i]=0;
}
void Mod(int *a,int *b,int *c,int n,int m){
while(!a[n-1])--n;
if(n<m){
fp(i,0,n-1)c[i]=a[i];fp(i,n,m-2)c[i]=0;
return;
}
static int A[N],B[N],IB[N],C[N];
R int len=1;while(len<=n-m)len<<=1;
fp(i,0,n-1)A[i]=a[n-i-1];fp(i,0,m-1)B[i]=b[m-i-1];
fp(i,m,len-1)B[i]=0;Inv(B,IB,len);
lim=(len<<1),d=lg[lim];
fp(i,n-m+1,lim-1)A[i]=IB[i]=0;
NTT(A,1),NTT(IB,1);
fp(i,0,lim-1)A[i]=mul(A[i],IB[i]);
NTT(A,0);
lim=1;while(lim<n)lim<<=1;d=lg[lim];
fp(i,0,n-m)C[i]=A[n-m-i];fp(i,n-m+1,lim-1)C[i]=0;
fp(i,0,m-1)B[i]=b[i];fp(i,m,lim-1)B[i]=0;
NTT(B,1),NTT(C,1);
fp(i,0,lim-1)B[i]=mul(B[i],C[i]);
NTT(B,0);
fp(i,0,m-2)c[i]=inc(a[i],P-B[i]);
fp(i,m-1,lim-1)c[i]=0;
}
void Mul(int *a,int *b,int *c,int n,int m){
static int A[N],B[N];
lim=1;while(lim<(n+m))lim<<=1;d=lg[lim];
fp(i,0,n-1)A[i]=a[i];fp(i,0,m-1)B[i]=b[i];
fp(i,n,lim-1)A[i]=0;fp(i,m,lim-1)B[i]=0;
NTT(A,1),NTT(B,1);
fp(i,0,lim-1)A[i]=mul(A[i],B[i]);
NTT(A,0);
fp(i,n+m-1,lim-1)A[i]=0;
Mod(A,md,c,n+m-1,K+1);
}
void ksm(int y){
R int sz=2,psz=1;
A[1]=1,B[0]=1;
for(;y;y>>=1,Mul(A,A,A,sz,sz),sz=sz+sz-1,cmin(sz,K))
if(y&1)Mul(A,B,B,sz,psz),psz+=sz-1,cmin(psz,K);
}
int main(){
// freopen("testdata.in","r",stdin);
init();
scanf("%d%d",&n,&K);
fp(i,1,K)scanf("%d",&a[i]),upd(a[i],P);
fp(i,0,K-1)scanf("%d",&b[i]),upd(b[i],P);
md[K]=1;fp(i,0,K-1)md[i]=inc(0,P-a[K-i]);
ksm(n);
R int res=0;
fp(i,0,K-1)upd(res,mul(B[i],b[i]));
printf("%d\n",res);
return 0;
}
参考文献
https://www.luogu.org/blog/ShadowassIIXVIIIIV/solution-p4723
https://blog.csdn.net/qq_39972971/article/details/80732541
CH定理与线性递推的更多相关文章
- 【模板】BM + CH(线性递推式的求解,常系数齐次线性递推)
这里所有的内容都将有关于一个线性递推: $f_{n} = \sum\limits_{i = 1}^{k} a_{i} * f_{n - i}$,其中$f_{0}, f_{1}, ... , f_{k ...
- 利用Cayley-Hamilton theorem 优化矩阵线性递推
平时有关线性递推的题,很多都可以利用矩阵乘法来解决. 时间复杂度一般是O(K3logn)因此对矩阵的规模限制比较大. 下面介绍一种利用利用Cayley-Hamilton theorem加速矩阵乘法的方 ...
- 【Luogu4723】线性递推(常系数齐次线性递推)
[Luogu4723]线性递推(常系数齐次线性递推) 题面 洛谷 题解 板子题QwQ,注意多项式除法那里每个多项式的系数,调了一天. #include<iostream> #include ...
- [NOI2017]泳池——概率DP+线性递推
[NOI2017]泳池 实在没有思路啊~~~ luogu题解 1.差分,转化成至多k的概率减去至多k-1的概率.这样就不用记录“有没有出现k”这个信息了 2.n是1e9,感觉要递推然后利用数列的加速技 ...
- [JZOJ6088] [BZOJ5376] [loj #2463]【2018集训队互测Day 1】完美的旅行【线性递推】【多项式】【FWT】
Description Solution 我们考虑将问题一步步拆解 第一步求出\(F_{S,i}\)表示一次旅行按位与的值为S,走了i步的方案数. 第二步答案是\(F_{S,i}\)的二维重复卷积,记 ...
- 求解线性递推方程第n项的一般方法
概述 系数为常数,递推项系数均为一次的,形如下面形式的递推式,称为线性递推方程. \[f[n]=\begin{cases} C &n\in Value\\ a_1 f[n-1]+a_2 f[n ...
- 矩阵乘法&矩阵快速幂&矩阵快速幂解决线性递推式
矩阵乘法,顾名思义矩阵与矩阵相乘, 两矩阵可相乘的前提:第一个矩阵的行与第二个矩阵的列相等 相乘原则: a b * A B = a*A+b*C a*c+b*D c d ...
- HDU - 6172:Array Challenge (BM线性递推)
题意:给出,三个函数,h,b,a,然后T次询问,每次给出n,求sqrt(an); 思路:不会推,但是感觉a应该是线性的,这个时候我们就可以用BM线性递推,自己求出前几项,然后放到模板里,就可以求了. ...
- POJ 2478 线性递推欧拉函数
题意: 求sigma phi(n) 思路: 线性递推欧拉函数 (维护前缀和) //By SiriusRen #include <cstdio> using namespace std; # ...
随机推荐
- Unity - 绘制正五边形网格
本文简述了Unity中绘制正五边形网格的基本方法:计算顶点信息.设置三角形覆盖信息.创建配置mesh 绘制方法 基本思路:计算出五边形顶点坐标信息作为数组,设置三角形包围方式,再创建新的mesh配置v ...
- 1、C#多线程基础理论
系统为应用程序分配所需的内存以及其他资源,内存和资源的物理分离叫做进程. 进程是以线程为单位竞争CPU,那么什么是线程呢? 线程可看成一个可执行的指令单元,他使用进程中的数据,包含若干条指令,进程 ...
- MySQL数据库之互联网常用分库分表方案
一.数据库瓶颈 不管是IO瓶颈,还是CPU瓶颈,最终都会导致数据库的活跃连接数增加,进而逼近甚至达到数据库可承载活跃连接数的阈值.在业务Service来看就是,可用数据库连接少甚至无连接可用.接下来就 ...
- Linux三剑客grep/sed/awk
grep/sed/awk被称为linux的“三剑客” grep更适合单纯的查找或匹配文本: sed更适合编辑匹配到的文本: awk更适合格式化文本,对文本进行较复杂各式处理: Grep --color ...
- Linux内核:关于中断你需要知道的
1.中断处理程序与其他内核函数真正的区别在于,中断处理程序是被内核调用来相应中断的,而它们运行于中断上下文(原子上下文)中,在该上下文中执行的代码不可阻塞.中断就是由硬件打断操作系统. 2.异常与中断 ...
- 代码实现排列组合【Java】
一.代码实现 package zhen; import java.util.Arrays; public class Arrangement { /** * 计算阶乘数,即n! = n * (n-1) ...
- 【TTS】传输表空间Linux asm -> AIX asm
[TTS]传输表空间Linux asm -> AIX asm 一.1 BLOG文档结构图 一.2 前言部分 一.2.1 导读和注意事项 各位技术爱好者,看完本文后,你可以掌 ...
- 【Java字节码】Idea中查看Java字节码的插件jclasslib Bytecode viewer
Idea插件搜索:jclasslib Bytecode viewer 安装完后,maven install你的项目(因为该插件会读取target下的class文件),然后选中某个java文件,按下图操 ...
- 【Docker】docker安装Jenkins
一.下载镜像 docker pull jenkinsci/jenkins 二.运行Jenkins容器 docker run --name myjenkins -d -p 8580:8080 -p 50 ...
- mysql考生号后三位对出密号
select mihao,substring(t1.kaohao, -3) from t_zhaosheng_zhiyuan as t1 where substring(t1.kaohao, -3) ...