矩阵优化递推式子

题目链接

对于f(n)=3f(n−1)+2f(n−2)+2这种式子,先将右边拥有的项竖着列出来,不包括系数,再将这个竖列的下一项写出来,然后将右边的每一项按照左边顺序的等式写出来,然后我们将等式右边只保留系数,那么这些系数就是我们需要的矩阵

        于是我们得到了系数矩阵,然后我们只需要求出系数矩阵的n-2次幂,最后再和第一项矩阵的乘积即可,也就是{f(2),f(1),2}(这是竖着的),也就是(1,1,2)。最后的左上角第一项就是答案f(n)。

        代码:

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
const int inf=0x3f3f3f3f;
typedef long long ll;
typedef pair<int,int> pii;
typedef unsigned long long ull;
//#define int long long
//const ll P=2281701377;
const ll P=998244353;
const int mod=1e9+7;
#define fi first
#define se second
#define int ll

struct node{
	int n,m;
	int a[5][5];
	node(){
		memset(a,0,sizeof(a));
	}
	node(int x){
		memset(a,0,sizeof(a));
		a[0][0]=a[1][1]=a[2][2]=x;
	}
	node operator *(const node &b){
		node res;
		for(int k=0;k<3;k++)
			for(int i=0;i<3;i++)
				for(int j=0;j<3;j++)
					res.a[i][j]=(res.a[i][j]+(ll)a[i][k]*b.a[k][j])%mod;
		return res;
	}
};

node qpow(node a,ll b){
	node s(1);
	while(b){
		if(b&1) s=s*a;
		a=a*a;
		b>>=1;
	}
	return s;
}


int n;
void solve(){
	cin>>n;
	node q;
	q.a[0][0]=q.a[1][0]=1,q.a[2][0]=2;
	node a;
	a.a[0][0]=3,a.a[0][1]=2,a.a[0][2]=1;
	a.a[1][0]=a.a[2][2]=1;
	if(n<=2)
		cout<<1<<endl;
	else{
		ll m=n-2;
		node t=qpow(a,m);
		t=t*q;
		cout<<t.a[0][0];
	}
}
signed main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int t=1;
    //cin>>t;
    while(t--){
        solve();
    }

}

题目链接        

和上题一样,就是将n-2次改成n-1次,因为f(n)的下标可以到0了,也就是可以多乘一个系数矩阵。系数矩阵和第一项矩阵:

          

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
const int inf=0x3f3f3f3f;
typedef long long ll;
typedef pair<int,int> pii;
typedef unsigned long long ull;
//#define int long long
//const ll P=2281701377;
const ll P=998244353;
const int mod=1e9+7;
#define fi first
#define se second
#define int ll

struct node{
	int n,m;
	int a[7][7];
	node(){
		memset(a,0,sizeof(a));
	}
	node(int x){
		memset(a,0,sizeof(a));
		for(int i=0;i<6;i++)
			a[i][i]=x;
	}
	node operator *(const node &b){
		node res;
		for(int k=0;k<6;k++)
			for(int i=0;i<6;i++)
				for(int j=0;j<6;j++)
					res.a[i][j]=(res.a[i][j]+(ll)a[i][k]*b.a[k][j])%mod;
		return res;
	}
};

node qpow(node a,ll b){
	node s(1);
	while(b){
		if(b&1) s=s*a;
		a=a*a;
		b>>=1;
	}
	return s;
}


int n;
void solve(){
	cin>>n;
	node q;
	q.a[0][0]=1,q.a[1][0]=0,q.a[2][0]=8,q.a[3][0]=4,q.a[4][0]=2,q.a[5][0]=1;
	node a;
	a.a[0][0]=a.a[0][1]=a.a[0][2]=a.a[0][3]=a.a[0][4]=a.a[0][5]=1;
	a.a[1][0]=1;
	a.a[2][2]=a.a[2][5]=1,a.a[2][3]=a.a[2][4]=3;
	a.a[3][3]=a.a[3][5]=1,a.a[3][4]=2;
	a.a[4][4]=a.a[4][5]=1;
	a.a[5][5]=1;
	if(n==0)
		cout<<0<<endl;
	else if(n==1)
		cout<<1<<endl;
	else{
		ll m=n-1;
		node t=qpow(a,m);
		t=t*q;
		cout<<t.a[0][0]<<endl;
	}
}
signed main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int t=1;
    cin>>t;
    while(t--){
        solve();
    }

}

  • 8
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值