Recursive sequence(快速矩阵幂模板)

该类题型适合大数,递推式及一个状态到另一个状态的规律

Problem Description

Farmer John likes to play mathematics games with his N cows. Recently, they are attracted by recursive sequences. In each turn, the cows would stand in a line, while John writes two positive numbers a and b on a blackboard. And then, the cows would say their identity number one by one. The first cow says the first number a and the second says the second number b. After that, the i-th cow says the sum of twice the (i-2)-th number, the (i-1)-th number, and i4. Now, you need to write a program to calculate the number of the N-th cow in order to check if John’s cows can make it right.

Input

The first line of input contains an integer t, the number of test cases. t test cases follow.
Each case contains only one line with three numbers N, a and b where N,a,b < 231 as described above.

Output

For each test case, output the number of the N-th cow. This number might be very large, so you need to output it modulo 2147493647.

Sample Input

2

3 1 2

4 1 10

Sample Output

85

369

Hint

In the first case, the third number is 85 = 2*1十2十3^4. In the second case, the third number is 93 = 2*1十1*10十3^4 and the fourth number is 369 = 2 * 10 十 93 十 4^4.

 

 

Source

2016ACM/ICPC亚洲区沈阳站-重现赛(感谢东北大学)

 该处分析转载,觉得确实分析很清楚。

题意:

已知递推公式:F(n) = 2*F(n-2) + F(n-1) + n4 和F(1) = a,F(2) = b;给定一个N,求F(N)等于多少?

由于N很大,直接递推肯定超时,所以要用到矩阵快速幂的知识log(n)的复杂度来解决。问题的关键就在于如何构造矩阵上,可以看出本题的递推公式是一个非线性的式子,所以要将非线性的部分展开为线性的。

注意:该处必须要凑的矩阵为n*n的,这样才能够自己相乘!!!n^4的拆分很巧妙

代码:

 //记住模板,关键还是在于找规律
#include "bits/stdc++.h"
#define rep(i,j,k) for(int i=j;i<=k;i++)
const int MOD = 1e5+7;
typedef long long ll;
using namespace std;
const int N =7;
ll mod = 2147493647;//必须是long long 
 
struct mat
{
	ll a[N][N];
};
 
mat mul_mat(mat &a,mat &b)
{
	mat res;
	memset(res.a,0,sizeof(res.a)); 
	rep(i,0,6)
		rep(j,0,6)
			rep(k,0,6)
			{
				res.a[i][j]=(res.a[i][j]+a.a[i][k]*b.a[k][j])%mod;
			}//就是这个位置了,之前用res.a[i][j]+a.a[i][k]*b.a[k][j]%mod;
                         //一直ac不了,还是要打括号保险
	return res;
}
mat pow_mat(ll n,mat &a)
{
	mat res;
	memset(res.a,0,sizeof(res.a));
	for(int i=0;i<=6;i++)
	res.a[i][i]=1;
	while(n)
	{
		if(n&1) res=mul_mat(res,a);
		a=mul_mat(a,a);
		n>>=1;
	}
	return res;
}
int main()
{
	int n;
	cin>>n;
	while(n--)
	{
		int a,b,m;
		cin>>m>>a>>b;
		int c[]={a,b,16,8,4,2,1};
		if(m==1)
		cout<<a<<endl;
		else if(m==2)
		cout<<a<<endl;
		else
		{
			mat res=
			{
				0,1,0,0,0,0,0,
				2,1,1,4,6,4,1,
				0,0,1,4,6,4,1,
				0,0,0,1,3,3,1,
				0,0,0,0,1,2,1,
				0,0,0,0,0,1,1,
				0,0,0,0,0,0,1,
			};
			mat cur=pow_mat(m-2,res);
			ll sum=0;
			for(int i=0;i<=6;i++)
			{
				sum=((sum+cur.a[1][i]*c[i])%mod);
			}
			cout<<sum<<endl;
		}
	}
	
	return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值