天天看點

軟體學院3.21天梯模拟 L3-2 我是送分題 (30 分)(矩陣快速幂,遞推)

題目:

大家最喜歡的送分題他來了,現在有一個等式F(n) = F(n - 1) + 2 * F(n - 2) + 3 * F(n - 3),F(1) = 1, F(2) = 2,F(3) = 3, 現在給出一個n請你求出F(n)對1e9+ 7取模.看到這裡你是不是想大喊一聲蕪湖,起飛,老送分題咯。

輸入格式:

簡簡單單一個n(4 <= n <= 1e9)

輸出格式:

輸出F(n)對1e9+ 7取模

輸入樣例:

在這裡給出一組輸入。例如:

4
           

輸出樣例:

在這裡給出相應的輸出。例如:

10
           

思路: 

這道題類似于斐波那契數列,也是給我們一個遞推式和前幾項,讓我們求第n項,值得注意的是n的範圍,

軟體學院3.21天梯模拟 L3-2 我是送分題 (30 分)(矩陣快速幂,遞推)

,那說明我們隻有通過

軟體學院3.21天梯模拟 L3-2 我是送分題 (30 分)(矩陣快速幂,遞推)

的做法才能夠通過此題,是以說開數組遞推或者是四個變量遞推這種

軟體學院3.21天梯模拟 L3-2 我是送分題 (30 分)(矩陣快速幂,遞推)

的做法必然會逾時的,實測開數組的做法能得8分,四個變量遞推能得10分,錯誤原因都是運作逾時,這也是意料之中

那麼怎麼才能做到

軟體學院3.21天梯模拟 L3-2 我是送分題 (30 分)(矩陣快速幂,遞推)

呢?

軟體學院3.21天梯模拟 L3-2 我是送分題 (30 分)(矩陣快速幂,遞推)

的算法比較少,常有的有兩個,最大公約數和快速幂,這題顯然與最大公約數無關,是以這道題用的是快速幂的思想

普通的快速幂是用來求解

軟體學院3.21天梯模拟 L3-2 我是送分題 (30 分)(矩陣快速幂,遞推)

 % p的問題,是通過倍增底數使得指數減半即:

軟體學院3.21天梯模拟 L3-2 我是送分題 (30 分)(矩陣快速幂,遞推)

,這樣這個算式就不用執行p次了,我們每次都倍增底數,都能使得指數減半,這種做法的時間複雜度是

軟體學院3.21天梯模拟 L3-2 我是送分題 (30 分)(矩陣快速幂,遞推)

的,雖然這題用到的是矩陣快速幂,但本質的思想是一樣的

這裡我們直接說結論,如下圖:

軟體學院3.21天梯模拟 L3-2 我是送分題 (30 分)(矩陣快速幂,遞推)

通過對這個矩陣進行幂運算,我們很輕易得就能得到,該遞推式的第n項,并成功把複雜度控制了下來,首先矩陣乘法的時間複雜度是

軟體學院3.21天梯模拟 L3-2 我是送分題 (30 分)(矩陣快速幂,遞推)

的,一共需要執行logn次,是以該算法的時間複雜度是

軟體學院3.21天梯模拟 L3-2 我是送分題 (30 分)(矩陣快速幂,遞推)

的,即便是n取到最大值1e9,log1e9約為30

代碼:

//7-18 我是送分題 (30 分)
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MOD = 1e9 + 7;

struct Matrix                                               //矩陣結構體
{
	ll m[3][3];                                             //3*3的矩陣
	
	Matrix()
	{
		memset(m , 0 , sizeof m);                           //通過構造函數初始化矩陣為零矩陣
	}    
};

Matrix mult(Matrix a , Matrix b)                            //3*3矩陣的乘法運算
{
	Matrix ans;
	for(int i = 0 ; i < 3 ; i++)
	{
		for(int j = 0 ; j < 3 ; j++)
		{
			ll sum = 0;
			for(int x = 0 ; x < 3 ; x++)
				sum = (sum + a.m[i][x] * b.m[x][j]) % MOD;
			ans.m[i][j] = sum;
		}
	}
	return ans;
}

Matrix pow(Matrix a , int b)                                //矩陣快速幂
{
	Matrix ans;
	ans.m[0][0] = ans.m[1][1] = ans.m[2][2] = 1;            //初始化機關矩陣
	while(b)
	{
		if(b & 1)
			ans = mult(ans , a);
		a = mult(a , a);
		b >>= 1;
	}
	
	return ans;
}

int main()
{
	int n;
	Matrix a;
	
	a.m[0][0] = a.m[1][0] = a.m[2][1] = 1;                 //構造目标矩陣
	a.m[0][1] = 2 , a.m[0][2] = 3;
	
	cin>>n;
	a = pow(a , n - 3);
	
	ll num[3][1] , ans[3][1];
	num[0][0] = 3 , num[1][0] = 2 , num[2][0] = 1;         //構造初始矩陣
	for(int i = 0 ; i < 3 ; i++)
	{
		for(int j = 0 ; j < 1 ; j++)
		{
			ll sum = 0;
			for(int x = 0 ; x < 3 ; x++)
				sum = (sum + a.m[i][x] * num[x][j]) % MOD;
			ans[i][j] = sum;
		}
	}
	
	cout<<ans[0][0]<<endl;
	return 0;
}