矩阵快速幂 从入门到入门

1.luogu P3216 [HNOI2011]数学作业

前言:

这sb题我竟然写了一下午,我TCL。
细节有点多,再加上我对矩阵快速幂的板子不熟,调了很长时间。

解析:

首先可以发现一个事情,不考虑进位的话,每次在末尾加一个数,相当于原数乘(10^k)再加上(i) ;
转移矩阵如下:(因为我Markdown太菜了不会打矩阵,就用这位大佬的题解里面的图了)

显然可以矩阵快速幂,因为每次的初始矩阵不一样,只要分段求就行了。
代码:

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
const int maxn=100000+10,N=3;
#define gc() (p1 == p2 ? (p2 = buf + fread(p1 = buf, 1, 1 << 20, stdin), p1 == p2 ? EOF : *p1++) : *p1++)
#define read() ({ register int x = 0, f = 1; register char c = gc(); while(c < '0' || c > '9') { if (c == '-') f = -1; c = gc();} while(c >= '0' && c <= '9') x = x * 10 + (c & 15), c = gc(); f * x; })
char buf[1 << 20], *p1, *p2;
ll ans,n,mod;
struct Matrix{
	ll c[5][5];
}A;
ll mul(ll x,ll y){
	ll res=0;
	ll base=x;
	while(y){
		if(y&1) res=(res+base)%mod;
		base=(base+base)%mod;
		y>>=1;
	}
	return res;
}
Matrix operator *(const Matrix &x,const Matrix &y){
	Matrix a;
	memset(a.c,0,sizeof(a.c));
	for(int i=1;i<=N;++i){
		for(int j=1;j<=N;++j){
			for(int k=1;k<=N;++k){
				a.c[i][j]=(a.c[i][j]+mul(x.c[i][k],y.c[k][j]))%mod;
			}
		}
	}
	return a;
}
ll qpow(ll x,ll y){
	ll res=1;
	ll base=x;
	while(y){
		if(y&1) res=mul(res,base);
		base=mul(base,base);
		y>>=1;
	}
	return res;
}
void clear(Matrix &s,int l){
	memset(s.c,0,sizeof(s.c));
	s.c[1][1]=qpow(1ll*10,l);
	s.c[1][2]=s.c[2][2]=s.c[2][3]=s.c[3][3]=1;
}
Matrix qp(ll x){
	Matrix s;
	memset(s.c,0,sizeof(s.c));
	for(int i=1;i<=N;++i) s.c[i][i]=1;
	while(x){
		if(x&1) s=A*s;
		A=A*A;
		x>>=1;
	}
	return s;
}
void Solve1(){
	ans= n ? 1 : 0 ;
	for(int i=2;i<=n;++i) ans=ans*10+i;
	printf("%llu",ans%mod);
}
void Solve(){
	scanf("%lld%lld",&n,&mod);
	if(n<10){
		Solve1();
		return;
	}
	ans=123456789%mod;
	ll now=99,len=2,last=10;
	while(now<n){
		clear(A,len);
		Matrix ccc=qp(now-last);
		ans=(mul(ans,qpow(10,len))+last)%mod;
		ans=(mul(ccc.c[1][1],ans)+mul(ccc.c[1][2],(last+1))+ccc.c[1][3])%mod;
		last=now+1;
		now=now*10+9;
		len++;
	}
	clear(A,len);
	Matrix ccc=qp(n-last);
	ans=(mul(ans,qpow(10,len))+last)%mod;
	ans=(mul(ccc.c[1][1],ans)+mul(ccc.c[1][2],(last+1))+ccc.c[1][3])%mod;
	printf("%llu",ans);
}
int main(){
	freopen("le.in","r",stdin);
	freopen("le.out","w",stdout);
	Solve();
	return 0;
}

2.luogu P1349 广义斐波那契数列

前言:

第一次接触矩阵快速幂,应该就是fibonacci数列了吧。
然而我还是调了好长时间,WTCL

解析:

转移矩阵:

没啥可说的,调了半小时发现自己初始矩阵写错了。。。
代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int n=2,maxn=4;
ll k,a1,a2,mod,p,q;
struct Matrix{
	ll c[maxn][maxn];
}A;
Matrix operator*(const Matrix &x,const Matrix &y){
	Matrix a;
	memset(a.c,0,sizeof(a.c));
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			for(int k=1;k<=n;++k){
				a.c[i][j]=(a.c[i][j]+x.c[i][k]*y.c[k][j]%mod)%mod;
			}
		}
	}
	return a;
}
Matrix qpow(){
	Matrix s;
	memset(s.c,0,sizeof(s.c));
	for(int i=1;i<=n;++i) s.c[i][i]=1;
	while(k){
		if(k&1) s=s*A;
		A=A*A;
		k>>=1;
	}
	return s;
}
void Solve(){
	scanf("%lld%lld%lld%lld%lld%lld",&p,&q,&a1,&a2,&k,&mod);
	if(k==1) {
		printf("%lld
",a1);
		return;
	}
	if(k==2){
		printf("%lld
",a2);
		return;
	}
	k-=2;
	memset(A.c,0,sizeof(A.c));
	A.c[1][1]=p;
	A.c[1][2]=q;
	A.c[2][1]=1;
	Matrix ans=qpow();
	printf("%lld
",(ans.c[1][1]*a2%mod+ans.c[1][2]*a1%mod)%mod);
}
int main(){
//	freopen("in","r",stdin);
//	freopen("out","w",stdout);
	Solve();
	return 0;
}

原文地址:https://www.cnblogs.com/wwcdcpyscc/p/13886147.html