Codeforce 1182 E. Product Oriented Recurrence(递推 + 矩阵快速幂 + 欧拉降幂)

在这里插入图片描述


f x = c 2 x − 6 ∗ f x − 1 ∗ f x − 2 ∗ f x − 3 f_x = c ^ {2x - 6} * f_{x - 1} * f_{x - 2}*f_{x-3} fx=c2x6fx1fx2fx3 c x f x = c x − 1 f x − 1 ∗ c x − 2 f x − 2 ∗ c x − 3 f x − 3 c^xf_x = c ^ {x - 1}f_{x - 1} * c^{x-2}f_{x - 2}*c^{x-3}f_{x-3} cxfx=cx1fx1cx2fx2cx3fx3 F x = c x ∗ f x F_x = c ^ x * f_x Fx=cxfx F 4 = F 1 ∗ F 2 ∗ F 3 F_4 = F_1 * F_2 * F_3 F4=F1F2F3 F 5 = F 4 ∗ F 3 ∗ F 2 = F 1 ∗ F 2 2 ∗ F 3 2 F_5 = F_4 * F_3 * F_2 = F_1 * F_2 ^2*F_3^2 F5=F4F3F2=F1F22F32 F 6 = F 5 ∗ F 4 ∗ F 3 = F 1 2 ∗ F 2 3 ∗ F 3 4 F_6 = F_5*F_4*F_3=F_1^2*F_2^3*F_3^4 F6=F5F4F3=F12F23F34 F 7 = F 6 ∗ F 5 ∗ F 4 F_7 = F_6 * F_5 * F_4 F7=F6F5F4即任意一项 F x F_x Fx都可以转化为 F 1 x 1 ∗ F 2 x 2 ∗ F 3 x 3 F_1 ^{x_1}*F_2^{x_2}*F_3^{x_3} F1x1F2x2F3x3,第7项及以后的项, x 1 = ( x − 1 ) 1 + ( x − 2 ) 1 + ( x − 3 ) 1 x_1 = (x-1)_1 + (x - 2)_1 + (x-3)_1 x1=(x1)1+(x2)1+(x3)1,对于 x 2 x_2 x2 x 3 x_3 x3也同样满足。
也就是说它的幂次是一个递推式,可以用矩阵快速幂进行加速,根据欧拉降幂来取模。根据递推式构造3阶递推矩阵,以及幂次的初始矩阵: F 4 , F 5 , F 6 F_4,F_5,F_6 F4,F5,F6的各项幂次构成初始矩阵。
这题就做完了


代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
ll a[5][5],tmp[5][5],c[5][5],ans[5][5];
ll b1[5][5],b2[5][5],b3[5][5];
ll n,f1,f2,f3,C;
void mul(ll a[5][5],ll b[5][5],ll p,int n,int m,int c) {
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= c; j++)
			tmp[i][j] = 0;
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= m; j++)
			for(int k = 1; k <= c; k++)
				tmp[i][k] += 1ll * a[i][j] * b[j][k] % p;
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= c; j++)
			a[i][j] = tmp[i][j];				
}
void mfpow(ll a[5][5],ll b,ll p,int n) {
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= n; j++)
			ans[i][j] = i == j;	
	while(b) {
		if(b & 1)
			mul(ans,a,p,n,n,n);
		b >>= 1;
		mul(a,a,p,n,n,n);
	}	
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= n; j++)
			a[i][j] = ans[i][j];
}
ll fpow(ll a,ll b) {
	ll r = 1;
	while(b) {
		if(b & 1) r = r * a % mod;
		a = a * a % mod;
		b >>= 1;
 	}
 	return r;
}
void solve(ll a[5][5],ll b[5][5],ll p,ll n,ll m,ll c) {
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= m; j++)
			ans[i][j] = a[i][j];
	mul(ans,b,p,n,m,c);
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= c; j++)
			b[i][j] = ans[i][j];
}
int main() {
	c[1][1] = c[1][2] = c[1][3] = 1;
	c[2][1] = c[3][2] = 1;
	b1[1][1] = 2,b1[2][1] = b1[3][1] = 1;
	b2[1][1] = 3,b2[2][1] = 2,b2[3][1] = 1;
	b3[1][1] = 4,b3[2][1] = 2,b3[3][1] = 1;
	ll a1,a2,a3;
	scanf("%lld%lld%lld%lld%lld",&n,&f1,&f2,&f3,&C);
	f1 = f1 * C % mod;
	f2 = f2 * fpow(C,2) % mod;
	f3 = f3 * fpow(C,3) % mod;
	ll p = fpow(C,n);
	ll inv = fpow(p,mod - 2);
	n -= 3;
	if(n > 3) {
		mfpow(c,n - 3,mod - 1,3);
		solve(c,b1,mod - 1,3,3,1);
		solve(c,b2,mod - 1,3,3,1);
		solve(c,b3,mod - 1,3,3,1);
		//printf("%lld %lld %lld\n",tmp[1][1],b2[1][1],b3[1][1]);
		a1 = fpow(f1,b1[1][1]);
		a2 = fpow(f2,b2[1][1]);
		a3 = fpow(f3,b3[1][1]);
	}
	else {
		a1 = fpow(f1,b1[3 - n + 1][1]);
		a2 = fpow(f2,b2[3 - n + 1][1]);
		a3 = fpow(f3,b3[3 - n + 1][1]);		
	}
	printf("%lld\n",a1 * a2 % mod * a3 % mod * inv % mod);	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值