Another kind of Fibonacci (個人賽19 hdu 3306)
Another kind of Fibonacci
Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 115 Accepted Submission(s): 50
Input There are several test cases.
Each test case will contain three integers , N, X , Y .
N : 2<= N <= 231 – 1
X : 2<= X <= 231– 1
Y : 2<= Y <= 231 – 1
Output For each test case , output the answer of S(n).If the answer is too big , divide it by 10007 and give me the reminder. Sample Input
2 1 1 3 2 3
6 196原來我們講的斐波那契數列是: F(0) = 1, F(1) = 1, F(N) = F(N - 1) + F(N - 2) 這道題規定了另一種斐波那契數列形式:A(0) = 1 , A(1) = 1 , A(N) = X * A(N - 1) + Y * A(N - 2) 其實原理是一樣的! 我們以前快速求Fibonacci數列f[n]=f[n-1]+f[n-2],f[1]=f[2]=1第n項的方法是!!??!! 構造常係數矩陣! (一)Fibonacci數列f[n]=f[n-1]+f[n-2],f[1]=f[2]=1的第n項的快速求法(不考慮高精度). 解法: 考慮1×2的矩陣【f[n-2],f[n-1]】。根據fibonacci數列的遞推關係,我們希望通過乘以一個2×2的矩陣,得到矩陣【f[n-1],f[n]】=【f[n-1],f[n-1]+f[n-2]】 很容易構造出這個2×2矩陣A,即: 0 1
1 1
1 1 0
0 1 1 問題(二)解決。 (三)數列f[n]=f[n-1]+f[n-2]+n+1,f[1]=f[2]=1的第n項的快速求法(不考慮高精度). 解法: 仿照前例,考慮1×4的矩陣【f[n-2],f[n-1],n,1】,希望求得某4×4的矩陣A,使得此1×4的矩陣乘以A得到矩陣: 【f[n-1],f[n],n+1,1】=【f[n-1],f[n-1]+f[n-2]+n+1,n+1,1】 容易構造出這個4×4的矩陣A,即: 0 1 0 0
1 1 0 0
0 1 1 0
0 1 1 1 問題(三)解決…… (四)數列f[n]=f[n-1]+f[n-2],f[1]=f[2]=1的前n項和s[n]的快速求法(不考慮高精度). 解法: 雖然我們有S[n]=F[n+2]-1,但本文不考慮此方法,我們想要得到更一般的方法。 考慮(一)的矩陣A,容易發現我們要求【f[1],f[2]】×(A+A2+A3+…+AN-1)。很多人使用一種很數學的方法構造一個2r*2r(r是A的階數,這裡為2)的矩陣來計算,這種方法比較麻煩且很慢,這裡不再介紹。下面考慮一種新方法。 仿照之前的思路,考慮1×3的矩陣【f[n-2],f[n-1],s[n-2]】,我們希望通過乘以一個3×3的矩陣A,得到1×3的矩陣: 【f[n-1],f[n],s[n-1]】=【f[n-1],f[n-1]+f[n-2],s[n-2]+f[n-1]】 容易得到這個3×3的矩陣是: 0 1 0
1 1 1
0 0 1 然後…………容易發現,這種方法的矩陣規模是(r+1)*(r+1),比之前流行的方法好得多。 (五)數列f[n]=f[n-1]+f[n-2]+n+1,f[1]=f[2]=1的前n項和s[n]的快速求法(不考慮高精度). 解法: 結合(三)(四),容易想到…… 考慮1×5的矩陣【f[n-2],f[n-1],s[n-2],n,1】, 我們需要找到一個5×5的矩陣A,使得它乘以A得到如下1×5的矩陣: 【f[n-1],f[n],s[n-1],n+1,1】 =【f[n-1], f[n-1]+f[n-2]+n+1,s[n-2]+f[n-1],n+1,1】 容易構造出A為: 0 1 0 0 0
1 1 1 0 0
0 0 1 0 0
0 1 0 1 0
0 1 0 1 1 然後……問題解決。 一般地,如果有f[n]=p*f[n-1]+q*f[n-2]+r*n+s 可以構造矩陣A為: 0 q 0 0 0
1 p 1 0 0
0 0 1 0 0
0 r 0 1 0
0 s 0 1 1 更一般的,對於f[n]=Sigma(a[n-i]*f[n-i])+Poly(n),其中0<i<=某常數c, Poly (n)表示n的多項式,我們依然可以構造類似的矩陣A來解決問題。 設Degree(Poly(n))=d, 並規定Poly(n)=0時,d=-1,此時對應於常係數線性齊次遞推關係。則本方法求前n項和的複雜度為: ((c+1)+(d+1))3*logns 所以對於這道題,
我們可以根據(s[n-2], a[n-1]^2, a[n-1]*a[n-2], a[n-2]^2) * A = (s[n-1], a[n]^2, a[n]*a[n-1], a[n-1]^2)
能夠求出關係矩陣
|1 0 0 0 |
A = |1 x^2 x 1 |
|0 2*x*y y 0 |
|0 y^2 0 0 |
這樣就A了!
#include <cstdio>
#include <cstring>
#include<iostream>
#include <algorithm>
using namespace std;
#define MOD 10007
struct Matrix
{
int numbers[4][4];
Matrix(int x = 0, int y = 0)
{
memset(numbers, 0, 4 * 4 * sizeof(int));
numbers[0][0] = numbers[0][1] = 1;
numbers[1][1] = x * x % MOD; numbers[1][2] = y * y % MOD; numbers[1][3] = 2 * x * y % MOD;
numbers[2][1] = 1;
numbers[3][1] = x; numbers[3][3] = y;
}
Matrix(bool flag)
{
memset(numbers, 0, 4 * 4 * sizeof(int));
numbers[0][0] = 1;
numbers[1][1] = 1;
numbers[2][2] = 1;
numbers[3][3] = 1;
}
};
Matrix operator * (const Matrix& lh, const Matrix& rh)
{
Matrix temp;
for (int i = 0; i < 4; ++i)
for (int j = 0; j < 4; ++j)
{
int sum = 0;
for (int k = 0; k < 4; ++k)
sum = (sum + lh.numbers[i][k] * rh.numbers[k][j]) % MOD;
temp.numbers[i][j] = sum;
}
return temp;
}
int main()
{
int n, x, y;
while (scanf("%u%u%u", &n, &x, &y) != EOF)
{
Matrix mat(x % MOD, y % MOD), res(true);
for (; n > 0; n >>= 1)
{
if (n & 1)
res = mat * res;
mat = mat * mat;
}
int sum = 0;
for (int i = 0; i < 4; ++i)
sum = (sum + res.numbers[0][i]) % MOD;
printf("%u/n", sum);
}
return 0;
}