1. 程式人生 > >Recursive sequence(快速矩陣冪模板)

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;
}