E. Product Oriented Recurrence(矩阵快速幂)

题目链接

题意:题目很容易理解,给出公式Fx = c^(2x-6)*Fx-1*Fx-2*Fx-3,然后给出n,c,F1,F2,F3,求Fn;

题解:看到这个公式就知道要套矩阵快速幂了。但这题比较特殊,要套两个矩阵快速幂。

1. 对于Fx

  •     F4 = F3 * F2 *F1;
  •     F5 = F3^2 * F2^2 * F1;
  •     F6 = F3^4 * F2^3 * F1^2;
  •     到F7时,F7的F1,F2,F3幂次方就等于F4,F5,F6的F1,F2,F3幂次方相加。
  •     F7 = F3^7 * F2^6 * F1^4;
  •     发现规律了吗?当推到F7项之后的递推式时,当前项的F1,F2,F3幂次方都等于前三项F1,F2,F3幂次方之和。
  •     所以F1,F2,F3其实分别都对应了一个关系矩阵,只是他们的关系矩阵相同而已。
  •     所以我们可以先求出这个关系矩阵,不同的只是带入的g1,g2,g3不同。
  •     设函数gn为第n项的幂次方。
  •     递推式gn = gn-1  + gn-2  + gn-3。
  •     最后得到关系矩阵

                  \begin{bmatrix} 1 & 1 & 1\\ 1 & 0&0 \\ 0& 1& 0 \end{bmatrix}\times\begin{bmatrix} gn-1\\ gn-2\\ gn-3 \end{bmatrix}= \begin{bmatrix} gn\\ gn-1\\ gn-2 \end{bmatrix}     

     

2.  对于C^(2*x-6)

    我们对这个函数的幂次方进行矩阵构造。

  •    F4 = C^2 = 2
  •    F5 = C^6 = 6
  •    F6 = C^14 = 14
  •    F7 = F4*F5*F6*C^8 = 2+6+14+8
  •    所以得到递推式Gn = Gn-1 + Gn-2 + Gn-3 + 2*n - 6
  •    这样就能很好的构造矩阵了

                    \begin{bmatrix} 1 &1 & 1 & 2& -4\\ 1& 0 & 0 &0 &0 \\ 0 & 1& 0& 0&0 \\ 0& 0& 0& 1&1 \\ 0& 0& 0 & 0 & 1 \end{bmatrix}\times \begin{bmatrix} Gn-1\\ Gn-2\\ Gn-3\\ n-1\\ 1 \end{bmatrix}= \begin{bmatrix} Gn\\ Gn-1\\ Gn-2\\ n\\ 1 \end{bmatrix}

要注意这是对他们的幂次方进行的矩阵构造。所以我们可以采取欧拉降幂。

其次因为第二个关系矩阵里存在负数,所以在求和的过程中要采取 (ans+mod)%mod的形式,保证其为正数。

 

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,f1,f2,f3,k;
const int mod = 1e9+7-1;
ll powmod(ll a,ll b) {ll res=1;a%=(mod+1); 
for(;b;b>>=1){if(b&1)res=res*a%(mod+1);a=a*a%(mod+1);}return res;}
struct mat{ll a[10][10];};
ll k1,k2,k3;
mat init(mat c,int len){//矩阵初始化 
	int b[4][4]={{1,1,1},
	            {1,0,0},
	            {0,1,0}};
	int t[6][6]={{1,1,1,2,-4},
	            {1,0,0,0,0},
				{0,1,0,0,0},
				{0,0,0,1,1},
				{0,0,0,0,1}};
	for(int i=0;i<len;i++)
	  for(int j=0;j<len;j++)
	    if(len==3) c.a[i][j]=b[i][j];
		else if(len==5) c.a[i][j]=t[i][j]; 
	return c;
}

mat mat_mul(mat x,mat y,int len){//矩阵快速乘 
	mat res;
	memset(res.a,0,sizeof res.a);
	for(int i=0;i<len;i++)
	   for(int j=0;j<len;j++)
	     for(int k=0;k<len;k++)
	    res.a[i][j] = (x.a[i][k]*y.a[k][j]+res.a[i][j]+mod)%mod;//可能存在负数,所以要+mod
	return res;
}

ll mat_pow(ll n,int len){//矩阵快速幂 
	mat c,res;
	c = init(c,len);
	ll m = n;
	memset(res.a,0,sizeof res.a);
	for(int i=0;i<len;i++) res.a[i][i] = 1;
	for(;n;n>>=1){
		if(n&1) res = mat_mul(res,c,len);
		c = mat_mul(c,c,len);
	}
	if(len==3) {//第一个矩阵 
		k1=res.a[0][0];
		k2=res.a[0][1];
		k3=res.a[0][2];
	}
	if(len==5){//第二个矩阵 
		ll ans = (res.a[0][0]*14+res.a[0][1]*6+res.a[0][2]*2
		  +res.a[0][3]*6+res.a[0][4]+mod)%mod;//可能存在负数所以要+mod
		return ans;//返回幂次方 
	}
	return 1;
}

int main()
{
	ll ans = 1;
	ll p[5][5]={{1,1,1,2},
	         {2,2,1,6},
			 {4,3,2,14}};
	cin>>n>>f1>>f2>>f3>>k;
	if(n<=6){//n小于6时不能用矩阵快速幂 
		ans = (ans*powmod(f3,p[n-4][0]))%(mod+1);
    	ans = (ans*powmod(f2,p[n-4][1]))%(mod+1);
    	ans = (ans*powmod(f1,p[n-4][2]))%(mod+1);
	    ans = ans*powmod(k,p[n-4][3])%(mod+1);
	}
	else {
		mat_pow(n-6,3);
	    ans = (ans*powmod(f3,(4*k1+2*k2+k3)%mod))%(mod+1);
    	ans = (ans*powmod(f2,(3*k1+2*k2+k3)%mod))%(mod+1);
    	ans = (ans*powmod(f1,(2*k1+1*k2+k3)%mod))%(mod+1);
	    ll t=mat_pow(n-6,5);
	    ans = ans*powmod(k,t%mod)%(mod+1);
	}
	cout<<ans<<endl;
}

 

     

     

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值