hdu 6395(矩阵快速幂)

 

Sequence

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 2573    Accepted Submission(s): 1004


 

Problem Description

Let us define a sequence as below



  Your job is simple, for each task, you should output Fn module 109+7.

 

 

Input

The first line has only one integer T, indicates the number of tasks.

Then, for the next T lines, each line consists of 6 integers, A , B, C, D, P, n.

1≤T≤200≤A,B,C,D≤1091≤P,n≤109

 

 

Sample Input

2

3 3 2 1 3 5

3 2 2 2 1 4

Sample Output

36

24

 

from:https://blog.csdn.net/weixin_39453270/article/details/81661394 

#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
const int maxn = 1e9 + 7;
long long a,b,c,d,p,n;
struct Marix {
	long long mo[3][3];
	Marix() {
		memset(mo,0,sizeof(mo));
	}
};
Marix mul(Marix a,Marix b) {
	Marix c;
	for(int i = 0;i < 3;i++) {
		for(int j = 0;j < 3;j++) {
			for(int k = 0;k < 3;k++) {
				c.mo[i][j] = (c.mo[i][j]+a.mo[i][k]*b.mo[k][j])%mod;
			}
		}
	}
	return c;
}
Marix powmod(Marix a,int n) {///矩阵快速幂模板
	Marix tmp;
	for(int i = 0;i < 3;i++) {
		tmp.mo[i][i] = 1;
	}
	while(n) {
		if(n&1) tmp = mul(tmp,a);
		n >>= 1;
		a = mul(a,a);
	}
	return tmp;
}


int main() {
	int T;
	scanf("%d",&T);
	while(T--) {
		scanf("%lld %lld %lld %lld %lld %lld",&a,&b,&c,&d,&p,&n);
		if(n == 1) {
			printf("%lld\n",a);
			continue;
		}
		if(n == 2) {
			printf("%lld\n",b);
			continue;
		}
		Marix m;
		m.mo[0][0] = d,
		m.mo[0][1] = c,
		m.mo[1][0] = 1,
		m.mo[2][2] = 1;
		bool vis = 0;
		for(int i = 3;i <= n;) {
			if(p/i == 0) {///倘若当前项大于p了,则直接用矩阵快速幂求解剩下的项
				Marix tmp;
				tmp = m;
				tmp = powmod(tmp,n-i+1);
				long long res = (tmp.mo[0][0]*b +tmp.mo[0][1]*a +tmp.mo[0][2])%mod;
				printf("%lld\n",res);
				vis = 1;
				break;
			}///否则,不断的分段求解矩阵的值,并将矩阵的值进行修改
			long long j = min(n,p/(p/i));
			Marix tmp;
			tmp = m;
			tmp.mo[0][2] = p/i;
			tmp = powmod(tmp,j-i+1);
			long long A = (tmp.mo[1][0]*b + tmp.mo[1][1]*a + tmp.mo[1][2]) % mod;
			long long B = (tmp.mo[0][0]*b + tmp.mo[0][1]*a + tmp.mo[0][2]) % mod;
			a = A,b = B;
			i = j+1;
		}
		if(!vis) printf("%lld\n",b);
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值