Product Oriented Recurrence (矩阵快速幂+欧拉扩展公式)

题目链接

https://cn.vjudge.net/problem/CodeForces-1182E
题目大意
fx=c2x−6⋅fx−1⋅fx−2⋅fx−3 for x≥4.
输入 n , f 1 , f 2 , f 3 , c n, f_1, f_2, f_3, c n,f1,f2,f3,c (4≤n≤1018, 1≤f1, f2, f3, c≤109).
输出 f n % ( 1 0 9 + 7 ) . f_n \%(10^9+7). fn%(109+7).

思路
我们可以将fn拆乘 (x个f1相乘)乘以(y个f2相乘)乘以(z个f3相乘)乘以 pow(c,k) 

   f3  f2  f1
1   0   0   1
2   0   1   0
3   1   0   0
4   1   1   1
5   2   2   1
6   4   3   2
7   7   6   4

从第四行开始
第n行的f1系数等于 第(n-1)行f1系数+(n-2)行f1系数+(n-3)行f1系数 
第n行的f2系数等于 第(n-1)行f2系数+(n-2)行f2系数+(n-3)行f2系数 
第n行的f3系数等于 第(n-1)行f3系数+(n-2)行f3系数+(n-3)行f3系数 

以f1为例
矩阵可以写成 
1 1 1     4 0 0
1 0 0  *  2 0 0
0 1 1     1 0 0

接下来就是求 pow(c,k);

1   1
2   1
3   1
4   pow(c,2)
5   pow(c,4)*pow(c,2)
6   pow(c,6)*pow(c,4)*pow(c,2)*pow(c,2)
7   pow(c,8)*pow(c,4)*pow(c,2)*pow(c,2) * pow(c,4)*pow(c,2) * pow(c,2)

从第四行开始
第n行为 第(n-1)行结果*(n-2)行结果*(n-3)行结果*pow(c,2*n-6) 

矩阵可以写成
 1  1  1  2 -6       14 0 0 0 0 
 1  0  0  0  0        6 0 0 0 0
 0  1  0  0  0   *    2 0 0 0 0 
 0  0  0  1  1        7 0 0 0 0 
 0  0  0  0  1        1 0 0 0 0
 

AC code
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define ll long long
const ll MOD = 1e9 + 7;
struct matrix{//矩阵快速幂
	ll m[5][5];
};
ll pow(ll x,ll n,ll mod){//快速幂
    ll res=1;
	while(n>0){
	   if(n%2==1){
	   	 res=res*x;
	   	 res=res%mod;
	   }
	   x=x*x;
	   x=x%mod;
	   n>>=1;
	}
	return res;
}

matrix matrix_multi(matrix a,matrix b){//矩阵相乘
	matrix tmp;
	for(int i=0;i<5;i++)
	for(int j=0;j<5;j++){
		tmp.m[i][j]=0;
		for(int k=0;k<5;k++)
			tmp.m[i][j]=((tmp.m[i][j])% (MOD-1) + (a.m[i][k]*b.m[k][j]+MOD-1)% (MOD-1)) % (MOD-1);
	}
	return tmp;
}

matrix matrix_pow(matrix a,matrix b,ll n){//矩阵快快速幂
	while(n>0){
		if(n&1) b=matrix_multi(a,b);
		a=matrix_multi(a,a);
		n>>=1;
	}
	return b;
}

ll ff3(ll f3, ll n){
	if(n==4) return pow(f3,1,MOD);
	if(n==5) return pow(f3,2,MOD);
	if(n==6) return pow(f3,4,MOD);
  matrix a,b;
	memset(a.m,0,sizeof a.m);
	memset(b.m,0,sizeof b.m);
	a.m[0][0]=1; a.m[0][1]=1; a.m[0][2]=1;
	a.m[1][0]=1; a.m[1][1]=0; a.m[1][2]=0;
	a.m[2][0]=0; a.m[2][1]=1; a.m[2][2]=0;

	b.m[0][0]=4; b.m[0][1]=0; b.m[0][2]=0;
	b.m[1][0]=2; b.m[1][1]=0; b.m[1][2]=0;
	b.m[2][0]=1; b.m[2][1]=0; b.m[2][2]=0;

	matrix ans=matrix_pow(a,b,n-6);
	return pow(f3,ans.m[0][0],MOD);
}

ll ff2(ll f2,ll n){
	if(n==4) return pow(f2,1,MOD);
	if(n==5) return pow(f2,2,MOD);
	if(n==6) return pow(f2,3,MOD);
	matrix a,b;
	memset(a.m,0,sizeof a.m);
	memset(b.m,0,sizeof b.m);
	a.m[0][0]=1; a.m[0][1]=1; a.m[0][2]=1;
	a.m[1][0]=1; a.m[1][1]=0; a.m[1][2]=0;
	a.m[2][0]=0; a.m[2][1]=1; a.m[2][2]=0;

	b.m[0][0]=3; b.m[0][1]=0; b.m[0][2]=0;
  b.m[1][0]=2; b.m[1][1]=0; b.m[1][2]=0;
  b.m[2][0]=1; b.m[2][1]=0; b.m[2][2]=0;

	matrix ans=matrix_pow(a,b,n-6);
	return pow(f2,ans.m[0][0],MOD);
}

ll ff1(ll f1,ll n){
	if(n==4) return pow(f1,1,MOD);
	if(n==5) return pow(f1,1,MOD);
	if(n==6) return pow(f1,2,MOD);
	matrix a,b;
	memset(a.m,0,sizeof a.m);
	memset(b.m,0,sizeof b.m);
	a.m[0][0]=1; a.m[0][1]=1; a.m[0][2]=1;
	a.m[1][0]=1; a.m[1][1]=0; a.m[1][2]=0;
	a.m[2][0]=0; a.m[2][1]=1; a.m[2][2]=0;

	b.m[0][0]=2; b.m[0][1]=0; b.m[0][2]=0;
	b.m[1][0]=1; b.m[1][1]=0; b.m[1][2]=0;
	b.m[2][0]=1; b.m[2][1]=0; b.m[2][2]=0;

	matrix ans=matrix_pow(a,b,n-6);
	return pow(f1,ans.m[0][0],MOD);
}

ll cc(ll c,ll n){

  if(n==4) return  pow(c,2,MOD);
  if(n==5) return  pow(c,6,MOD);
  if(n==6) return  pow(c,14,MOD);
  matrix a,b;
	memset(a.m,0,sizeof a.m);
	memset(b.m,0,sizeof b.m);
  b.m[0][0]=14;
  b.m[1][0]=6;
  b.m[2][0]=2;
  b.m[3][0]=7;
  b.m[4][0]=1;

  a.m[0][0]=1; a.m[0][1]=1; a.m[0][2]=1; a.m[0][3]=2; a.m[0][4]=-6;
  a.m[1][0]=1; a.m[1][1]=0; a.m[1][2]=0; a.m[1][3]=0; a.m[1][4]=0;
  a.m[2][0]=0; a.m[2][1]=1; a.m[2][2]=0; a.m[2][3]=0; a.m[2][4]=0;
  a.m[3][0]=0; a.m[3][1]=0; a.m[3][2]=0; a.m[3][3]=1; a.m[3][4]=1;
  a.m[4][0]=0; a.m[4][1]=0; a.m[4][2]=0; a.m[4][3]=0; a.m[4][4]=1;

  matrix ans=matrix_pow(a,b,n-6);
	return pow(c,ans.m[0][0],MOD);
}

void solve(){
	ll n,f1,f2,f3,c;
	scanf("%lld %lld %lld %lld %lld", &n, &f1, &f2, &f3, &c);
	if(n==1){
    printf("%lld\n", f1);
    return ;
  }
  if(n==2){
    printf("%lld\n", f2);
    return ;
  }
  if(n==3){
    printf("%lld\n", f3);
    return ;
  }
	ll anss=1;
	 anss=( anss * ff1(f1,n))%MOD;
	 anss=( anss * ff2(f2,n))%MOD;
	 anss=( anss * ff3(f3,n))%MOD;
	 anss=( anss * cc(c,n))%MOD;
  printf("%lld\n", anss);
	return ;
}

int main(){
	solve();
  return 0;
}

为什么要在矩阵相乘里面要MOD-1呢?
因为矩阵算出来的 x , y , z , k x, y, z, k x,y,z,k 意思是 f 1 x , f 2 y , f 3 z , c k f_1^x, f_2^y, f_3^z, c^k f1x,f2y,f3z,ck
又因欧拉定理的推论:
若正整数a,n互质,那么对于任意正整数b,有ab≡ab mod φ(n)(mod n)
所以最终结果是
( f 1 ( x % M O D − 1 ) × f 2 y % M O D − 1 × f 1 z % M O D − 1 × c k % M O D − 1 ) % M O D (f_1^{(x\%MOD-1)}\times f_2^{y\%MOD-1}\times f_1^{z\%MOD-1}\times c^{k\%MOD-1})\%MOD (f1(x%MOD1)×f2y%MOD1×f1z%MOD1×ck%MOD1)%MOD

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值