递归构造之矩阵快速幂

递归构造之矩阵快速幂
一.前提须知:在这里插入图片描述
二.各种递推公式构造
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;    
}
  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿斯卡码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值