bzoj 4162 shlw loves matrix II - 行列式 - 矩阵乘法 - 高斯消元

本文深入探讨了如何利用矩阵快速幂算法求解大规模矩阵的幂运算问题,通过构造矩阵的特征多项式,将问题转化为线性递推的形式,进而利用快速幂算法高效求解。文章详细介绍了算法的实现步骤,包括多项式乘法、矩阵乘法和快速幂运算,并提供了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意:
给一个n * n的矩阵A,求其k次方。 n ≤ 50 , k ≤ 2 10000 n\le50,k\le2^{10000} n50,k210000
题解:
考虑将 A k A^k Ak视为某个数列的第k项 h k h_k hk(严格意义上是矩阵列?)
尝试改造 h h h的递推式。
考虑: F ( x ) = ∣ A − x I ∣ F(x)=|A-xI| F(x)=AxI即A减去若干倍的单位矩阵求行列式。
以3*3的矩阵为例,它张这个样子:
F ( x ) = ∣ A 1 , 1 − x A 1 , 2 A 1 , 3 A 2 , 1 A 2 , 2 − x A 2 , 3 A 3 , 1 A 3 , 2 A 3 , 3 − x ∣ F(x)=\left|\begin{matrix} A_{1,1}-x & A_{1,2} & A_{1,3} \\ A_{2,1} & A_{2,2}-x & A_{2,3} \\ A_{3,1} & A_{3,2} & A_{3,3}-x \\ \end{matrix}\right| F(x)=A1,1xA2,1A3,1A1,2A2,2xA3,2A1,3A2,3A3,3x
显然其会是一个关于x的n次多项式。
那么根据定义有: F ( A ) = 0 F(A)=0 F(A)=0(啥你问我为啥带入的不是实数而是个矩阵?其实严格的说法是,把F的系数copy一遍弄出一个新的以矩阵为变量的函数F’,然后根据某个C开头的定理F’(A)=0,不过直观"理解" F ( A ) = ∣ A − I A ∣ = 0 F(A)=|A-IA|=0 F(A)=AIA=0
总之把这个多项式的系数插值出来,可以知道:
∑ i = 0 n f i A i = 0 \sum_{i=0}^nf_iA^i=0 i=0nfiAi=0
那么我要求第k项:
∑ i = 0 n f i A i + k − n = ∑ i = 0 n f n − i A k − i = 0 \sum_{i=0}^nf_iA^{i+k-n}=\sum_{i=0}^nf_{n-i}A^{k-i}=0 i=0nfiAi+kn=i=0nfniAki=0
或者说:
∑ i = 0 n f n − i h k − i = 0 \sum_{i=0}^nf_{n-i}h_{k-i}=0 i=0nfnihki=0
因此可以通过 h k − n , … , h k − 1 h_{k-n},\dots,h_{k-1} hkn,,hk1算出 h k h_k hk,套用常系数线性递推即可。
复杂度 O ( n 4 + n 2 l g k ) O\left(n^4+n^2lgk\right) O(n4+n2lgk),复杂度瓶颈在于算n次行列式和预处理 h 0 , . . . , h n − 1 h_0,...,h_{n-1} h0,...,hn1

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define mod 1000000007
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
	int x,ch;while((ch=gc)<'0'||ch>'9');
	x=ch^'0';while((ch=gc)>='0'&&ch<='9')
		x=(x<<1)+(x<<3)+(ch^'0');return x;
}
const int N=53;int v[N][N],vs[N][N],a[N][N],b[N];
inline int fast_pow(int x,int k,int ans=1) { for(;k;k>>=1,x=(lint)x*x%mod) (k&1)?ans=(lint)ans*x%mod:0;return ans; }
inline int calc(int n,int x)
{
	rep(i,1,n) memcpy(vs[i],v[i],sizeof(int)*(n+1));
	rep(i,1,n) v[i][i]-=x,(v[i][i]<0?v[i][i]+=mod:0);
	int det=1;
	rep(i,1,n)
	{
		int x=i;rep(j,i,n) if(v[j][i]) x=j;
		if(i^x) swap(v[i],v[x]),det=(det?mod-det:0);
		if(!v[i][i]) { det=0;break; }x=fast_pow(v[i][i],mod-2);
		rep(j,i,n) v[i][j]=(lint)v[i][j]*x%mod;det=(lint)det*x%mod;
		rep(j,i+1,n) { x=v[j][i];rep(k,i,n) v[j][k]-=(lint)x*v[i][k]%mod,(v[j][k]<0?v[j][k]+=mod:0); }
	}
	rep(i,1,n) memcpy(v[i],vs[i],sizeof(int)*(n+1));
	return det?fast_pow(det,mod-2):0;
}
inline int gauss(int (*a)[N],int *b,int n)
{
	rep(i,0,n)
	{
		int x=i;rep(j,i,n) if(a[j][i]) x=j;
		swap(a[i],a[x]),swap(b[i],b[x]),x=fast_pow(a[i][i],mod-2);
		rep(j,i,n) a[i][j]=(lint)a[i][j]*x%mod;b[i]=(lint)b[i]*x%mod;
		rep(j,0,n) if(i^j)
		{
			x=a[j][i];if(!x) continue;
			rep(k,i,n) a[j][k]-=(lint)x*a[i][k]%mod,(a[j][k]<0?a[j][k]+=mod:0);
			b[j]-=(lint)x*b[i]%mod,(b[j]<0?b[j]+=mod:0);
		}
	}
	return 0;
}
struct matrix{
#define P(k) (lint)a.v[i][k]*b.v[k][j]
	int v[N][N],n;matrix(int _n=0) { init(_n); }
	inline int init(int _n=0) { n=_n;rep(i,1,n) memset(v[i],0,sizeof(int)*(n+1));return 0; }
	inline matrix operator*(const matrix &b)const
	{
		const matrix &a=*this;matrix c(n);
		rep(i,1,n) rep(k,1,n) rep(j,1,n) c.v[i][j]=(c.v[i][j]+P(k))%mod;
		return c;
	}
	inline matrix& operator*=(const matrix &b) { return (*this)=(*this)*b; }
	inline matrix operator+(const matrix &b)const
	{
		const matrix &a=*this;matrix c(n);
		rep(i,1,n) rep(j,1,n) c.v[i][j]=a.v[i][j]+b.v[i][j],(c.v[i][j]>=mod?c.v[i][j]-=mod:0);
		return c;
	}
	inline matrix& operator+=(const matrix &b) { return (*this)=(*this)+b; }
	inline matrix operator*(int x)const
	{
		const matrix &a=*this;matrix c(n);
		rep(i,1,n) rep(j,1,n) c.v[i][j]=(lint)a.v[i][j]*x%mod;
		return c;
	}
	inline matrix& operator*=(int x) { return (*this)=(*this)*x; }
	inline int print()const { rep(i,1,n) rep(j,1,n) printf("%d%c",v[i][j]," \n"[j==n]);return 0; }
}A,B,ans;
struct poly{
	int v[N<<1],n;
	poly() { memset(v,0,sizeof v),n=0; }
	inline poly operator*(const poly &b)const
	{
		const poly &a=*this;poly c;
		c.n=a.n+b.n;
		rep(i,0,a.n) rep(j,0,b.n)
			c.v[i+j]=(c.v[i+j]+(lint)a.v[i]*b.v[j])%mod;
		return c;
	}
	inline poly& operator*=(const poly &b) { return (*this)=(*this)*b; }
	inline int mul(int *b,int m)
	{
		int t=fast_pow(b[m],mod-2);
		for(int i=n;i>=m;i--)
		{
			int x=(lint)v[i]*t%mod;
			rep(j,0,m) v[i-j]-=(lint)b[m-j]*x%mod,(v[i-j]<0?v[i-j]+=mod:0);
		}
		return n=m-1;
	}
	inline int show()const { debug(n)ln;rep(i,0,n) cerr<<v[i]sp;cerr ln;return 0; }
}ansp;
inline int polymul(char *k,int *b,int n)
{
	poly x;ansp.n=0,ansp.v[0]=1;x.v[0]=0,x.v[1]=1,x.n=1;
	for(int i=(int)strlen(k+1);i;i--,x*=x,x.mul(b,n))
		if(k[i]=='1') ansp*=x,ansp.mul(b,n);return 0;
}
char k[100010];
int main()
{
	scanf("%s",k+1);int n=inn();
	rep(i,1,n) rep(j,1,n) v[i][j]=inn();
	rep(i,0,n)
	{
		b[i]=calc(n,i);
		rep(j,a[i][0]=1,n) a[i][j]=(lint)a[i][j-1]*i%mod;
	}
	gauss(a,b,n),polymul(k,b,n);
	A.init(n),B.init(n),ans.init(n);
	rep(i,1,n) A.v[i][i]=1;
	rep(i,1,n) rep(j,1,n) B.v[i][j]=v[i][j];
	rep(i,0,n-1) ans+=A*ansp.v[i],A*=B;
	return ans.print();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值