递归构造之矩阵快速幂
一.前提须知:
二.各种递推公式构造
1.缺项型(1)//AC
//include<bits/stdc++.h>
#include<cstring>
#include<iostream>
#include<cstdio>
using namespace std;
const int N=12;
int mod;
/*
10 9999
1 1 1 1 1 1 1 1 1 1
20 500
1 0 1 0 1 0 1 0 1 0
*/
struct mat{
int m[N][N];
};
mat operator*(mat a,mat b)
{
mat res;
memset(res.m ,0,sizeof(res.m ));
for(int i=0;i<10;i++)
{
for(int j=0;j<10;j++)
{
for(int k=0;k<10;k++)
res.m [i][j]=res.m [i][j]+a.m [i][k]*b.m [k][j];
res.m [i][j]%=mod;
}
}
return res;
}
mat quickpow(mat a,int k)
{
mat res;
memset(res.m ,0,sizeof(res.m ));
for(int i=0;i<10;i++)
res.m [i][i]=1;
while(k)
{
if(k&1)res=res*a;
k>>=1;
a=a*a;
}
return res;
}
int main()
{
mat cst,a;
memset(cst.m,0,sizeof(cst.m));
int k;
while(scanf("%d%d",&k,&mod)!=EOF)
{
//构造cst
for(int i=0;i<10;i++)
{
scanf("%d",&cst.m [0][i]);
}
for(int i=0;i<9;i++)
cst.m [i+1][i]=1;
//条件判断
if(k<=9)printf("%d\n",k%mod);
else
{
a=quickpow(cst,k-9);
int sum=0;
for(int i=0;i<10;i++)
sum=sum+a.m [0][i]*(9-i);
printf("%d\n",sum%mod);
}
}
}
2.常数型
3.含有变量型(1)//Time Limit Exceeded
#include<cstring>
#include<iostream>
#include<cstdio>
using namespace std;
const int N=12;
int mod=123456789;
int n=6;
struct mat{
int m[N][N];
};
mat operator*(mat a,mat b)
{
mat res;
memset(res.m ,0,sizeof(res.m ));
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
for(int k=0;k<n;k++)
res.m [i][j]=res.m [i][j]+(a.m [i][k]*b.m [k][j])%mod;
res.m [i][j]%=mod;
}
}
return res;
}
mat quickpow(mat a,int k)
{
mat res;
memset(res.m ,0,sizeof(res.m ));
for(int i=0;i<n;i++)
res.m [i][i]=1;
while(k)
{
if(k&1)res=res*a;
k>>=1;
a=a*a;
}
return res;
}
/*
5
3
6
9
12
15
31
700
7486
64651
527023
*/
int main()
{
mat cst,a;
int cns,l;
scanf("%d",&cns);
cst.m [0][0]=1,cst.m [0][1]=2,cst.m [0][2]=1,cst.m [0][3]=3,cst.m [0][4]=3,cst.m [0][5]=1;
cst.m [1][0]=1,cst.m [1][1]=0,cst.m [1][2]=0,cst.m [1][3]=0,cst.m [1][4]=0,cst.m [1][5]=0;
cst.m [2][0]=0,cst.m [2][1]=0,cst.m [2][2]=1,cst.m [2][3]=3,cst.m [2][4]=3,cst.m [2][5]=1;
cst.m [3][0]=0,cst.m [3][1]=0,cst.m [3][2]=0,cst.m [3][3]=1,cst.m [3][4]=2,cst.m [3][5]=1;
cst.m [4][0]=0,cst.m [4][1]=0,cst.m [4][2]=0,cst.m [4][3]=0,cst.m [4][4]=1,cst.m [4][5]=1;
cst.m [5][0]=0,cst.m [5][1]=0,cst.m [5][2]=0,cst.m [5][3]=0,cst.m [5][4]=0,cst.m [5][5]=1;
while(n--)
{
scanf("%d",&l);
a=quickpow(cst,l-2);//快速幂调用
unsigned long long int sum=0;
sum=a.m [0][0]*2+a.m [0][1]+a.m [0][2]*8+a.m [0][3]*4+a.m [0][4]*2+a.m [0][5];
printf("%lld\n",sum%mod);
}
}
4.正常前缀和型(1)//AC
#include<cstring>
#include<iostream>
#include<cstdio>
#define int long long//避免数据溢出
using namespace std;
const int N=12;//不变量一定const,不然m[N][N]定义错误
const int mod=1000000007;
int n=4;
struct mat{
int m[N][N];//int矩阵乘法会溢出 ,long long 不会
};
//0 2
//0 5
//3
//20
mat operator*(mat a,mat b)
{
mat res;
memset(res.m ,0,sizeof(res.m ));
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
for(int k=0;k<n;k++)
res.m [i][j]=(res.m [i][j]%mod+(a.m [i][k]*b.m [k][j])%mod)%mod;
}
}
return res;
}
mat quickpow(mat a,int k)
{
mat res;
memset(res.m ,0,sizeof(res.m ));
for(int i=0;i<n;i++)
res.m [i][i]=1;
while(k)
{
if(k&1)res=res*a;
k>>=1;
a=a*a;
}
return res;
}
int sum(int x,mat cst)
{
if(x < 0) return 0;
else if(x == 0) return 1;
else if(x == 1) return 2;
else if(x == 2) return 3;
mat ma;
ma = quickpow(cst, x-2);
return (3*ma.m[0][0]%mod+ma.m[0][1]%mod+ma.m[0][2]%mod+ma.m[0][3]%mod)%mod;
}
//1 2 3 6 11 20
//1 1 1 3 5 9
signed main()//由于#define定义,所以用signed
{
mat cst,a,b;
int bn,an;
memset(cst.m,0,sizeof(cst.m));
cst.m [0][0]=1,cst.m [0][1]=1,cst.m [0][2]=1,cst.m [0][3]=1;
cst.m [1][0]=0,cst.m [1][1]=1,cst.m [1][2]=1,cst.m [1][3]=1;
cst.m [2][0]=0,cst.m [2][1]=1,cst.m [2][2]=0,cst.m [2][3]=0;
cst.m [3][0]=0,cst.m [3][1]=0,cst.m [3][2]=1,cst.m [3][3]=0;
while(~scanf("%lld%lld",&an,&bn))//long long
{
if(an==bn)printf("%lld\n",sum(bn,cst)%mod);
else {
int resb = sum(bn,cst)%mod;
int resa = sum(an-1,cst)%mod;
int res = (resb-resa+mod)%mod;//+mod,因为resb可能小于resa,成为负数
printf("%lld\n",res);
}
}
return 0;
}
5.平方前缀和型(1)//AC
#include<cstring>
#include<iostream>
#include<cstdio>
//#define int long long
using namespace std;
const int N=12;
int mod=10007;
int n=4;
struct mat{
int m[N][N];
};
mat operator*(mat a,mat b)
{
mat res;
memset(res.m ,0,sizeof(res.m ));
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
for(int k=0;k<n;k++)
res.m [i][j]=(res.m [i][j]+(a.m [i][k]*b.m [k][j])%mod)%mod;
}
}
return res;
}
mat quickpow(mat a,int k)
{
mat res;
memset(res.m ,0,sizeof(res.m ));
for(int i=0;i<n;i++)
res.m [i][i]=1;
while(k)
{
if(k&1)res=res*a;
k>>=1;
a=a*a;
}
return res;
}
//2 1 1
//3 2 3
//6
//196
int main()
{
mat cst,a;
memset(cst.m,0,sizeof(cst.m));
int l,x,y;
while(scanf("%d%d%d",&l,&x,&y)!=EOF)
{
//可以mod的都mod,尽量都mod
x=x%mod,y=y%mod;
//构造cst
cst.m [0][0]=1%mod,cst.m [0][1]=x*x%mod,cst.m [0][2]=2*x*y%mod,cst.m [0][3]=y*y%mod;
cst.m [1][0]=0%mod,cst.m [1][1]=x*x%mod,cst.m [1][2]=2*x*y%mod,cst.m [1][3]=y*y%mod;
cst.m [2][0]=0%mod,cst.m [2][1]=x%mod,cst.m [2][2]=y%mod,cst.m [2][3]=0%mod;
cst.m [3][0]=0%mod,cst.m [3][1]=1%mod,cst.m [3][2]=0%mod,cst.m [3][3]=0%mod;
if(l==0)printf("%d",1);
else if(l==1)printf("%d",2);
else {
a=quickpow(cst,l-1);//快速幂调用
int sum=0;
sum=a.m [0][0]*2%mod+a.m [0][1]%mod+a.m [0][2]%mod+a.m [0][3]%mod;
printf("%d\n",sum%mod);
}
}
}
6.数字01交替型(1)//NOmake
题目来源
空
三.简单题目//AC
A.题目来源
#include<cstdio>//printf(),scanf()
#include<iostream>//cin>>,cout<<
#include<cstring>//memset()
#define int long long//避免数据溢出
//#include<bits/stdc++.h> poj无法进行
using namespace std;
const int N=10;
int n=2;
int mod=10000;
struct mat {
int m[N][N];
};
//或mat mul(mat a,mat b)//矩阵乘法
mat operator * (mat a,mat b)
{
mat res;
memset(res.m,0,sizeof(res.m));
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
for(int k=0;k<n;k++)
res.m[i][j]=(res.m[i][j]+(a.m[i][k]*b.m[k][j])%mod)%mod;
}
return res;
}
mat quickpow(mat a,int k)
{
mat res;//单位矩阵
memset(res.m,0,sizeof(res.m));
for(int i=0;i<n;i++)//n矩阵维数
res.m [i][i]=1;
while(k){//快速幂
if(k&1)res=res*a;
k>>=1;
a=a*a;
}
return res;
}
signed main()
{
int input;//指数
mat cst,a;
//由题意构造cst矩阵,即所需快速幂矩阵
cst.m [0][0]=1;
cst.m [0][1]=1;
cst.m [1][0]=1;
cst.m [1][1]=0;
while(cin>>input&&input!=-1)
{
if(input<=0)cout<<0<<endl;
else
{
a=quickpow(cst,input-1);
cout<<(a.m[0][0])%mod<<endl;//如图第2种方法
}
}
return 0;
}
B.题目来源
#include<cstdio>//printf(),scanf()
#include<iostream>//cin>>,cout<<
#include<cstring>//memset()
//#include<bits/stdc++.h> // poj无法进行
using namespace std;
const int N=12;
int mod=9973;
int n;
struct mat {
int m[N][N];
};
//或mat mul(mat a,mat b)//矩阵乘法
mat operator * (mat a,mat b)
{
mat res;
memset(res.m,0,sizeof(res.m));
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
for(int k=0;k<n;k++)
res.m[i][j]+=a.m[i][k]*b.m[k][j];
res.m[i][j]%=mod;
}
return res;
}
mat quickpow(mat a,int k)
{
mat res;//单位矩阵
memset(res.m,0,sizeof(res.m));
for(int i=0;i<n;i++)//n矩阵维数
res.m [i][i]=1;
while(k){//快速幂
if(k&1)res=res*a;
k>>=1;
a=a*a;
}
return res;
}
int main()
{
int l,k;//指数
mat cst,a;
cin>>l;
while(l--)
{
cin>>n>>k;
//所需快速幂矩阵
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
cin>>cst.m [i][j];
a=quickpow(cst,k);
int sum=0;
for(int i=0;i<n;i++)
sum=sum+a.m [i][i];
printf("%d\n",sum%mod);
}
return 0;
}
四.模板
#include<cstring>
#include<iostream>
#include<cstdio>
#define int long long//避免数据溢出
using namespace std;
const int N=12;//不变量一定const,不然m[N][N]定义错误
const int mod=1000000007;
int n=4;
struct mat{
int m[N][N];//int矩阵乘法会溢出 ,long long 不会
};
//0 2
//0 5
//3
//20
mat operator*(mat a,mat b)
{
mat res;
memset(res.m ,0,sizeof(res.m ));
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
for(int k=0;k<n;k++)
res.m [i][j]=(res.m [i][j]%mod+(a.m [i][k]*b.m [k][j])%mod)%mod;
}
}
return res;
}
mat quickpow(mat a,int k)
{
mat res;
memset(res.m ,0,sizeof(res.m ));
for(int i=0;i<n;i++)
res.m [i][i]=1;
while(k)
{
if(k&1)res=res*a;
k>>=1;
a=a*a;
}
return res;
}
int sum(int x,mat cst)
{
if(x < 0) return 0;
else if(x == 0) return 1;
else if(x == 1) return 2;
else if(x == 2) return 3;
mat ma;
ma = quickpow(cst, x-2);
return (3*ma.m[0][0]%mod+ma.m[0][1]%mod+ma.m[0][2]%mod+ma.m[0][3]%mod)%mod;
}
//1 2 3 6 11 20
//1 1 1 3 5 9
signed main()//由于#define定义,所以用signed
{
mat cst,a,b;
int bn,an;
memset(cst.m,0,sizeof(cst.m));
cst.m [0][0]=1,cst.m [0][1]=1,cst.m [0][2]=1,cst.m [0][3]=1;
cst.m [1][0]=0,cst.m [1][1]=1,cst.m [1][2]=1,cst.m [1][3]=1;
cst.m [2][0]=0,cst.m [2][1]=1,cst.m [2][2]=0,cst.m [2][3]=0;
cst.m [3][0]=0,cst.m [3][1]=0,cst.m [3][2]=1,cst.m [3][3]=0;
while(~scanf("%lld%lld",&an,&bn))//long long
{
if(an==bn)printf("%lld\n",sum(bn,cst)%mod);
else {
int resb = sum(bn,cst)%mod;
int resa = sum(an-1,cst)%mod;
int res = (resb-resa+mod)%mod;//+mod,因为resb可能小于resa,成为负数
printf("%lld\n",res);
}
}
return 0;
}