矩阵快速幂
矩阵必须全部初始化,注意矩阵大小
最简单的矩阵快速幂
f[n]=f[n-1]+f[n-2]
ac:
#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;
/*
(f(n-1),f(n-2))*(1,1 =(f(n),f(n-1))
1,0)
*/
const ll mod=10000;//mod
const int N=2;
struct Matrix{
ll a[N][N];
Matrix(){
memset(a,0,sizeof(a));
}
};
Matrix mul(Matrix A,Matrix B)
{
Matrix C;
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
for(int k=0;k<N;k++)
C.a[i][j]=(C.a[i][j]+A.a[i][k]*B.a[k][j])%mod;
return C;
}
Matrix pow_mod(Matrix A,ll n)
{
Matrix B;//原矩阵
B.a[0][0]=1;
B.a[0][1]=1;
while(n)
{
if(n&1) B=mul(B,A);
A=mul(A,A);
n=n>>1;
}
return B;
}
int main()
{
ll n;
Matrix G;
int c[2][2]={1,1,//构造矩阵
1,0};
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
G.a[i][j]=c[i][j];
while(scanf("%lld",&n)&&n!=-1)
{
if(n==0)
printf("%d\n",0);
else if(n==1)
printf("%d\n",1);
else{
Matrix res=pow_mod(G,n-2);
printf("%lld\n",res.a[0][0]);
}
}
return 0;
}
f(n)=f(n-1)+2*f(n-2)+n^4
f(1)=a,f(2)=b
(n+1)^4=n^4+4*n^3+6*n^2+4^n+1
构造的矩阵长宽为7*7
ac:
#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;
const ll mod=2147493647;
const int N=7;
int aa,bb;
struct Matrix{
ll a[N][N];
Matrix(){
memset(a,0,sizeof(a));
}
};
Matrix mul(Matrix A,Matrix B)
{
Matrix C;
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
for(int k=0;k<N;k++)
C.a[i][j]=(C.a[i][j]+A.a[i][k]*B.a[k][j])%mod;
return C;
}
Matrix pow_mod(Matrix A,ll n)
{
Matrix B;
B.a[0][0]=bb;
B.a[0][1]=aa;
B.a[0][2]=16;
B.a[0][3]=8;
B.a[0][4]=4;
B.a[0][5]=2;
B.a[0][6]=1;
while(n)
{
if(n&1) B=mul(B,A);
A=mul(A,A);
n=n>>1;
}
return B;
}
int main()
{
ll t,n;
Matrix G;
int c[7][7]={
1,1,0,0,0,0,0,
2,0,0,0,0,0,0,
1,0,1,0,0,0,0,
4,0,4,1,0,0,0,
6,0,6,3,1,0,0,
4,0,4,3,2,1,0,
1,0,1,1,1,1,1};
for(int i=0;i<7;i++)
for(int j=0;j<7;j++)
G.a[i][j]=c[i][j];
cin>>t;
while(t--)
{
cin>>n>>aa>>bb;
if(n==0)
cout<<0<<endl;
else if(n==1)
cout<<aa<<endl;
else{
Matrix res=pow_mod(G,n-2);
cout<<res.a[0][0]%mod<<endl;
}
}
return 0;
}
链接:https://ac.nowcoder.com/acm/contest/221/C
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
令f(n)=2*f(n-1)+3*f(n-2)+n,f(1)=1,f(2)=2
令g(n)=g(n-1)+f(n)+n*n,g(1)=2
告诉你n,输出g(n)的结果,结果对1e9+7取模
输入描述:
多组输入,每行一个整数n(1<=n<=1e9),如果输入为0,停止程序。
输出描述:
在一行中输出对应g(n)的值,结果对1e9+7取模。
示例1
输入
1
5
9
456
0
输出
2
193
11956
634021561
说明
多组输入,输入为0时,终止程序
备注:
项数极大,朴素算法无法在规定时间内得出结果
解析:
矩阵快速幂求解:
原矩阵:(g(n-1),f(n),f(n-1),n^2,n,1)
{
1,0,0,0,0,0,
1,2,1,0,0,0,
0,3,0,0,0,0,
1,0,0,1,0,0,
0,1,0,2,1,0,
0,1,0,1,1,1};
=>(g(n),f(n+1),f(n),(n+1)^2,n+1,1)
这里g(n)只与g(n-1)有关,所以构造矩阵要求(n-1)的次方
ac:
#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;
const int mod=1e9+7;//mod
const int N=6;//构造矩阵的长宽
struct Matrix{
ll a[N][N];
Matrix(){
memset(a,0,sizeof(a));
}
};
Matrix mul(Matrix A,Matrix B)
{
Matrix C;
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
for(int k=0;k<N;k++)
C.a[i][j]=(C.a[i][j]+A.a[i][k]*B.a[k][j])%mod;
return C;
}
Matrix pow_mod(Matrix A,ll n)
{
Matrix B;//原矩阵
B.a[0][0]=2;
B.a[0][1]=2;
B.a[0][2]=1;
B.a[0][3]=4;
B.a[0][4]=2;
B.a[0][5]=1;
while(n)
{
if(n&1) B=mul(B,A);
A=mul(A,A);
n=n>>1;
}
return B;
}
int main()
{
int n;
Matrix G;
int c[6][6]={
1,0,0,0,0,0,
1,2,1,0,0,0,
0,3,0,0,0,0,
1,0,0,1,0,0,
0,1,0,2,1,0,
0,1,0,1,1,1};//构造矩阵
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
G.a[i][j]=c[i][j];
while(scanf("%d",&n)&&n!=0)
{
if(n==0)
{
printf("0\n");
}
else if(n==1)
{
printf("2\n");
}
else{
Matrix res=pow_mod(G,n-1);
printf("%lld\n",res.a[0][0]);
//printf("%lld\n",res.a[0][2]);
}
}
return 0;
}
链接:https://ac.nowcoder.com/acm/contest/105/G
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
这是一个加强版的斐波那契数列。
给定递推式F(i)=⎧⎪⎨⎪⎩F(i−1)+F(i−2)+i3+i2+i+1i>10i=01i=1F(i)={F(i−1)+F(i−2)+i3+i2+i+1i>10i=01i=1
求F(n)的值,由于这个值可能太大,请对109+7取模。
输入描述:
第一行是一个整数T(1 ≤ T ≤ 1000),表示样例的个数。
以后每个样例一行,是一个整数n(1 ≤ n ≤ 1018)。
输出描述:
每个样例输出一行,一个整数,表示F(n) mod 1000000007。
示例1
输入
4
1
2
3
100
输出
1
16
57
558616258
解析:
直接列出即可
注意B矩阵的构造,n是3
ac:
#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;
const ll mod=1e9+7;//mod
const int N=6;//构造矩阵的长宽
struct Matrix{
ll a[N][N];
Matrix(){
memset(a,0,sizeof(a));
}
};
Matrix mul(Matrix A,Matrix B)
{
Matrix C;
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
for(int k=0;k<N;k++)
C.a[i][j]=(C.a[i][j]+A.a[i][k]*B.a[k][j])%mod;
return C;
}
Matrix pow_mod(Matrix A,ll n)
{
Matrix B;//原矩阵
B.a[0][0]=16;
B.a[0][1]=1;
B.a[0][2]=27;
B.a[0][3]=9;
B.a[0][4]=3;
B.a[0][5]=1;
while(n)
{
if(n&1) B=mul(B,A);
A=mul(A,A);
n=n>>1;
}
return B;
}
int main()
{
ll n,t;
Matrix G;
ll c[6][6]={
1,1,0,0,0,0,
1,0,0,0,0,0,
1,0,1,0,0,0,
1,0,3,1,0,0,
1,0,3,2,1,0,
1,0,1,1,1,1,};//构造矩阵
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
G.a[i][j]=c[i][j];
scanf("%d",&t);
while(t--)
{
scanf("%lld",&n);
if(n==0)
{
printf("0\n");
}
else if(n==1)
{
printf("1\n");
}
else{
Matrix res=pow_mod(G,n-2);
printf("%lld\n",res.a[0][0]);//新矩阵的f[n]的位置
}
}
return 0;
}
E. Product Oriented Recurrence
解析:
f(x)=f(x-1)*f(x-2)*f(x-3)*C^(2*x-6)
给定n,f1,f2,f3,和c求fn
解析:
列出几项后发现
f(n)=f1^a*f2^b*f3^c*c^d
an=a(n-1)+a(n-2)+a(n-3)
bn=b(n-1)+b(n-2)+b(n-3)
cn=c(n-1)+c(n-2)+c(n-3)
dn=d(n-1)+d(n-2)+d(n-3)+2*n-6
我们用四个矩阵快速幂求an,bn,cn,dn
这个式子可以通过四个矩阵快速幂求各系数+欧拉降幂解决
ac:
#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;
const ll mod=1000000006;//phi(1000000007)
const ll mod2=1000000007;
const int N=100;
ll x,y,z;
struct Matrix{
ll a[N][N];
Matrix(){
memset(a,0,sizeof(a));
}
};
Matrix mul(Matrix A,Matrix B,int sz)
{
Matrix C;
for(int i=0;i<sz;i++)
for(int j=0;j<sz;j++)
for(int k=0;k<sz;k++)
C.a[i][j]=(C.a[i][j]+A.a[i][k]*B.a[k][j])%mod;
return C;
}
Matrix pow_mod(Matrix B,Matrix A,ll n,int sz)
{
while(n)
{
if(n&1) B=mul(B,A,sz);
A=mul(A,A,sz);
n=n>>1;
}
return B;
}
ll qpow(ll a,ll b)
{
ll ans=1;
a=a%mod2;
while(b)
{
if(b&1) ans=(ans*a)%mod2;
a=(a*a)%mod2;
b>>=1;
}
return ans;
}
int main()
{
ll n,k;
Matrix G;
ll cc[3][3]={
1,1,0,
1,0,1,
1,0,0};
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
G.a[i][j]=cc[i][j];
ll dd[5][5]={
1,1,0,0,0,
1,0,1,0,0,
1,0,0,0,0,
2,0,0,1,0,
-6,0,0,1,1};
Matrix H;
for(int i=0;i<5;i++)
for(int j=0;j<5;j++)
H.a[i][j]=dd[i][j];
cin>>n>>x>>y>>z>>k;
Matrix A,B,C,D;
A.a[0][0]=2,A.a[0][1]=1,A.a[0][2]=1;
B.a[0][0]=3,B.a[0][1]=2,B.a[0][2]=1;
C.a[0][0]=4,C.a[0][1]=2,C.a[0][2]=1;
D.a[0][0]=14,D.a[0][1]=6,D.a[0][2]=2,D.a[0][3]=7,D.a[0][4]=1;
A=pow_mod(A,G,n-4,3);
B=pow_mod(B,G,n-4,3);
C=pow_mod(C,G,n-4,3);
D=pow_mod(D,H,n-4,5);
ll va=A.a[0][2];
ll vb=B.a[0][2];
ll vc=C.a[0][2];
ll vd=D.a[0][2];
/*
a^b=a^(b%phi(mod)+phi(mod))%mod
这里要欧拉降幂,前面的阶乘x,x=x%phi(mod),phi(1000000007)=1000000006
所以前面用的是mod=1000000006;
后面求pow用mod;
*/
ll x1=qpow(x,va+mod);
ll x2=qpow(y,vb+mod);
ll x3=qpow(z,vc+mod);
ll x4=qpow(k,vd+mod);
ll sum=(x1*x2)%mod2;
sum=(sum*x3)%mod2;
sum=(sum*x4)%mod2;
printf("%lld\n",sum);
return 0;
}
https://ac.nowcoder.com/acm/contest/885/B
题意:
求指数非常大(大数)的矩阵快速幂,用10进制暴力计算,预处理0-9的情况
ac:
#include <bits/stdc++.h>
#define N 2
using namespace std;
typedef long long ll;
const int maxn = 1e6+5;
char n[maxn];
ll Mod;
ll x0,x1,a,b;
int len;
ll cnt=0;
struct matrix
{
ll a[N+1][N+1];
friend matrix operator*(matrix A,matrix B)
{
matrix C;
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
C.a[i][j]=0;
for(int k=0;k<N;k++){
C.a[i][j]=(C.a[i][j]+A.a[i][k]*B.a[k][j])%Mod;
}
}
}
return C;
}
}p[31];
matrix qpow(matrix A,int m)//方阵A的m次幂
{
matrix ans;//单位矩阵
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
ans.a[i][j]=(i==j);
while(m)
{
if(m&1) ans=ans*A;
A=A*A;
m>>=1;
}
return ans;
}
matrix ppow(matrix x,char *b)
{
len = strlen(b);
matrix ans,A,res;
ans.a[0][0] = x1,ans.a[0][1] = x0;
A.a[0][0]=A.a[1][1]=1;
int sub = 0;
res=qpow(x,b[0]-'0'-1);
for(int i=1;i<len;i++)
{
res=qpow(res,10);
int m=b[i]-'0'+9;
//matrix tmp=qpow(x,m);预处理,加速
res=res*p[m];
}
ans=ans*res;
return ans;
}
matrix init()
{
matrix f;
f.a[0][0] = a; f.a[0][1] = 1;
f.a[1][0] = b; f.a[1][1] = 0;
p[1]=f;
for(int i=2;i<=21;i++)
p[i]=p[i-1]*f;
return f;
}
int main()
{
scanf("%lld%lld%lld%lld",&x0,&x1,&a,&b);
scanf("%s%lld",n+1,&Mod);
matrix f=init();
matrix ans = ppow(f,n+1);
printf("%lld\n",ans.a[0][0]);
}
https://vjudge.net/problem/POJ-3233
题意:
给定一个矩阵A,求A+A^2+A^3+A^4+...+A^n
解析:
=>
=>
我们发现规律
|A , 1| |A^n , 1+A^1+A^2+....+A^(n-1)|
|0 , 1| 的n次方等于 |0 , 1 |
我们直接构造一个长宽为2n的矩阵A',将矩阵分成4份,左上为A,右上,右下为单位矩阵
然后求pow(A',k),输出右上部分(a[i][j]-1+m)%m的结果
ac:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define ll long long
#define N 101
using namespace std;
ll mod;
int sz;
struct matrix
{
ll a[N+1][N+1];
friend matrix operator*(matrix A,matrix B)
{
matrix C;
for(int i=0;i<sz;i++){
for(int j=0;j<sz;j++){
C.a[i][j]=0;
for(int k=0;k<sz;k++){
C.a[i][j]=(C.a[i][j]+A.a[i][k]*B.a[k][j])%mod;
}
}
}
return C;
}
};
matrix qpow(matrix A,ll m)//方阵A的m次幂
{
matrix ans;//单位矩阵
for(int i=0;i<sz;i++)
ans.a[i][i]=1;
while(m)
{
if(m&1) ans=ans*A;
A=A*A;
m>>=1;
}
return ans;
}
int main()
{
ll n,k,m;
scanf("%lld%lld%lld",&n,&k,&m);
mod=m;
sz=n*2;
matrix A;
for(int i=0;i<sz;i++)
for(int j=0;j<sz;j++)
A.a[i][j]=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
scanf("%lld",&A.a[i][j]);
A.a[i][i+n]=A.a[i+n][i+n]=1;
}
A=A*qpow(A,k);
for(int i=0;i<n;i++)
A.a[i][i+n]=(A.a[i][i+n]-1+m)%m;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
printf("%lld",A.a[i][j+n]);
printf("%s",j<n-1?" ":"\n");
}
}
return 0;
}
/*
3 99999 4
1 2 3
4 5 6
7 8 9
*/