矩阵快速幂
https://www.luogu.com.cn/problem/P3390
就是矩阵乘法+快速幂,本来想用宏定义定义mod,结果不知道为什么会出错,改成const就过了
//#include<iostream>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const ll max_n=1e5+1000;
const ll inf=0x3f3f3f3f;
ll n,m,a[120][120];
struct mat{
int len;
ll m[110][110];
mat times(mat b){
mat c;
c.len=len;
for(int i=0;i<len;i++){
for(int j=0;j<len;j++){
ll res=0;
for(int v=0;v<len;v++){
res+=m[i][v]*b.m[v][j]%mod;
}c.m[i][j]=(res+mod)%mod;
}
}
return c;
}
void output(){
for(int i=0;i<len;i++){
for(int j=0;j<len;j++){
cout<<m[i][j]<<' ';
}cout<<endl;
}
}
void uni(){
for(int i=0;i<len;i++){
for(int j=0;j<len;j++){
if(i==j) m[i][j]=1;
else m[i][j]=0;
}
}
}
};
mat qmp(mat a,ll k){
mat res,x;
res.len=a.len;
x.len=a.len;
res.uni(),x=a;
while(k){
if(k&1){
res=res.times(x);
}x=x.times(x);
k>>=1;
}
return res;
}
int main(){
//freopen("in.txt","r",stdin);
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>m;
mat a;
a.len=n;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin>>a.m[i][j];
}
}
qmp(a,m).output();
return 0;
}
矩阵加速
https://www.luogu.com.cn/problem/P1939
板子题,矩阵长这样:
\(
\left[ \begin{array}{c}
a_n\\
a_{n-1}\\
a_{n-2}\\
\end{array} \right] =\left[ \begin{matrix}
1& 0& 1\\
1& 0& 0\\
0& 1& 0\\
\end{matrix} \right] \left[ \begin{array}{c}
\begin{array}{c}
a_{\begin{array}{c}
n-1\\
\end{array}}\\
a_{n-2}\\
\end{array}\\
a_{n-3}\\
\end{array} \right]
\)
然后就是套上快速幂求就可以了,结果就是第一行的和
//#include<iostream>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const ll max_n=1e5+1000;
const ll inf=0x3f3f3f3f;
ll n,m,a[120][120];
struct mat{
int len;
ll m[110][110];
mat times(mat b){
mat c;
c.len=len;
for(int i=0;i<len;i++){
for(int j=0;j<len;j++){
ll res=0;
for(int v=0;v<len;v++){
res+=m[i][v]*b.m[v][j]%mod;
}c.m[i][j]=(res+mod)%mod;
}
}
return c;
}
void output(){
for(int i=0;i<len;i++){
for(int j=0;j<len;j++){
cout<<m[i][j]<<' ';
}cout<<endl;
}
}
void uni(){
for(int i=0;i<len;i++){
for(int j=0;j<len;j++){
if(i==j) m[i][j]=1;
else m[i][j]=0;
}
}
}
};
mat qmp(mat a,ll k){
mat res,x;
res.len=a.len;
x.len=a.len;
res.uni(),x=a;
while(k){
if(k&1){
res=res.times(x);
}x=x.times(x);
k>>=1;
}
return res;
}
int main(){
//freopen("in.txt","r",stdin);
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n;
mat a,ans;
a.len=3;
a.m[0][0]=1,a.m[0][1]=0,a.m[0][2]=1;
a.m[1][0]=1,a.m[1][1]=0,a.m[1][2]=0;
a.m[2][0]=0,a.m[2][1]=1,a.m[2][2]=0;
while(n--){
cin>>m;
if(m<=3){
cout<<1<<endl;
continue;
}else{
ans=qmp(a,m-3);
ll res=(ans.m[0][0]+ans.m[0][1]+ans.m[0][2])%mod;
cout<<res<<endl;
}
}
return 0;
}
斐波那契公约数
https://www.luogu.com.cn/problem/P1306
事实证明,打表乃找规律第一要义,打出来前20x20个结果,发现结果总就那么几个值,又发现这些值全是本身数列里的元素,结果就可以得到以下规律:
\[gcd\left( f_n,f_m \right) =f_{gcd\left( n,m \right)}
\]
然后就简单了,同上。
//#include<iostream>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e8;
const ll max_n=1e5+1000;
const ll inf=0x3f3f3f3f;
ll n,m,a[120][120];
struct mat{
int len;
ll m[110][110];
mat times(mat b){
mat c;
c.len=len;
for(int i=0;i<len;i++){
for(int j=0;j<len;j++){
ll res=0;
for(int v=0;v<len;v++){
res+=m[i][v]*b.m[v][j]%mod;
}c.m[i][j]=(res+mod)%mod;
}
}
return c;
}
void output(){
for(int i=0;i<len;i++){
for(int j=0;j<len;j++){
cout<<m[i][j]<<' ';
}cout<<endl;
}
}
void uni(){
for(int i=0;i<len;i++){
for(int j=0;j<len;j++){
if(i==j) m[i][j]=1;
else m[i][j]=0;
}
}
}
};
mat qmp(mat a,ll k){
mat res,x;
res.len=a.len;
x.len=a.len;
res.uni(),x=a;
while(k){
if(k&1){
res=res.times(x);
}x=x.times(x);
k>>=1;
}
return res;
}
ll gcd(ll a,ll b){
if(b==0){
return a;
}else return gcd(b,a%b);
}
int main(){
//freopen("in.txt","r",stdin);
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>m;
mat a,ans;
a.len=2;
a.m[0][0]=1,a.m[0][1]=1;
a.m[1][0]=1,a.m[1][1]=0;
n=gcd(n,m);
if(n<=2){
cout<<1<<endl;
}else{
ans=qmp(a,n-2);
cout<<(ans.m[0][0]+ans.m[0][1])%mod<<endl;
}
return 0;
}