矩阵快速幂
算法封装模板
点击查看代码
struct matrix {
vector<vector<int>>a,b;
int n;
matrix (int n1):n(n1),a(n1,vector<int>(n1,0)),b(n1,vector<int>(n1,0)){}
matrix operator-(const mat& T) const {
matrix res(n);
for(int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j) {
res.a[i][j] = (a[i][j] - T.a[i][j]) % mod;
}
return res;
}
matrix operator+(const mat& T) const {
matrix res(n);
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j){
res.a[i][j] = (a[i][j] + T.a[i][j]) % mod;
}
return res;
}
matrix operator*(const mat& T) const {
matrix res(n);
int r;
for (int i = 0; i < n; ++i)
for (int k = 0; k < n; ++k) {
r = a[i][k];
for (int j = 0; j < n; ++j)
res.a[i][j] += T.a[k][j] * r, res.a[i][j] %= mod;
}
return res;
}
matrix operator^(int x) const {
matrix res(n), bas(n);
for (int i = 0; i < n; ++i) res.a[i][i] = 1;
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j) bas.a[i][j] = b[i][j]%mod;
while (x) {
if (x & 1) res = res * bas;
bas = bas * bas;
x >>= 1;
}
return res;
}
};
例题
[例题](https://atcoder.jp/contests/abc293/tasks/abc293_e?lang=en)
思路
从题意可知,这个题明显不能用逆元,因为用费马小定理的限制是模数mod必须是质数。
而使用扩展欧几里得求逆元的条件是这个公式中\(ax \equiv 1 \pmod m\)必须满足\(gcd(a,m)==1\)条件,很明显这个题目是不满足的,
所以我们可以考虑使用矩阵加速来解决这个问题,\(x<=1e12\),因此使用\(log(n)\)的时间复杂度是可以满足的.
推式子可以知道
\[f(n) = a \times f(n-1) + 1 \times 1
\]
\[\begin{pmatrix}
f_x \\[6pt]
1
\end{pmatrix}
=
\begin{pmatrix}
a & 0 \\[3pt]
1 & 1
\end{pmatrix}^{x}
\;
\begin{pmatrix}
f_0 \\[6pt]
1
\end{pmatrix}
\]
所以最后只用求出
\[T^x \;=\;
\begin{pmatrix}
p & q \\
r & s
\end{pmatrix}
\]
$$ \begin{pmatrix} f_x \\ 1 \end{pmatrix} = T^x \begin{pmatrix} f_0 \\ 1 \end{pmatrix} = \begin{pmatrix} p & q \\ r & s \end{pmatrix} \begin{pmatrix} f_0 \\ 1 \end{pmatrix} = \begin{pmatrix} pf_0 + q \\ rf_0 + s \end{pmatrix} $$
$$ f_x \;=\; p\,f_0 + q. $$
以下是代码
点击查看代码
#include<bits/stdc++.h>
#define fi first
#define se second
#define int long long
#define PII pair<int,int>
using namespace std;
const int N=5e6+10,M=1e9,mod=1e9+7;
int MOD;
int qim(int a,int k,int m){
int res=1;
while(k){
if(k&1)res=res*a%m;
k>>=1;
a=a*a%m;
}
return res;
}
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
int lcm(int a,int b){
return a*b/gcd(a,b);
}
struct mat {
vector<vector<int>>a;
int n;
mat (int n1):n(n1),a(n,vector<int>(n,0)){}
mat operator-(const mat& T) const {
mat res(n);
for(int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j) {
res.a[i][j] = (a[i][j] - T.a[i][j]) % MOD;
}
return res;
}
mat operator+(const mat& T) const {
mat res(n);
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j){
res.a[i][j] = (a[i][j] + T.a[i][j]) % MOD;
}
return res;
}
mat operator*(const mat& T) const {
mat res(n);
int r;
for (int i = 0; i < n; ++i)
for (int k = 0; k < n; ++k) {
r = a[i][k];
for (int j = 0; j < n; ++j)
res.a[i][j] += T.a[k][j] * r, res.a[i][j] %= MOD;
}
return res;
}
mat operator^(int x) const {
mat res(n), bas(n);
for (int i = 0; i < n; ++i) res.a[i][i] = 1;
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j) bas.a[i][j] = a[i][j] % MOD;
while (x) {
if (x & 1) res = res * bas;
bas = bas * bas;
x >>= 1;
}
return res;
}
};
//int e[N],ne[N],h[N],idx,w[N],in[N],out[N];
//void add(int a,int b,int c){
// e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
//}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int _=1;
//cin>>_;
while(_--){
int a,x,m;cin>>a>>x>>m;
MOD=m;
mat ma(2);
ma.a[0][0]=a%m,ma.a[0][1]=1;
ma.a[1][1]=1;
ma=(ma^x);
cout<<ma.a[0][1]<<'\n';
}
return 0;
}
用矩阵加速$log(n)$解决斐波那契数列: $$ f(n)=f(n-1)+f(n-2) $$
因此可以构造矩阵 $$ \begin{pmatrix} f_n \\ f_{n-1} \end{pmatrix} = \begin{pmatrix} f_{n-1} \times 1 + f_{n-2} \times 1\\ f_{n-1} \times 1 + f_{n-2} \times 0\\ \end{pmatrix} = \begin{pmatrix} 1 & 1 \\ 1 & 0 \end{pmatrix} \times \begin{pmatrix} f_{n-1}\\ f_{n-2} \end{pmatrix} $$ 因此可以化成 $$ \begin{pmatrix} f_{n-1}\\ f_{n-2} \end{pmatrix} = \begin{pmatrix} 1 & 1\\ 1 & 0 \end{pmatrix} ^{n-2} \times \begin{pmatrix} f_{2}\\ f_{1} \end{pmatrix} $$