Another kind of Fibonacci
Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1175 Accepted Submission(s): 446
Each test case will contain three integers , N, X , Y .
N : 2<= N <= 2 31 – 1
X : 2<= X <= 2 31– 1
Y : 2<= Y <= 2 31 – 1
2 1 1 3 2 3
6 196
这种题目,难就难在构造矩阵上面,如果能够成功的构造出矩阵,那么剩下的内容都好解决,如果没有构造出来,那么就一点思路都没有了,没有构造出来。。。还是看别人的解题过程吧。
矩阵连乘求解。
首先我们列一个式子 A(n)=x*A(n-1)+b*A(n-2);
则A(n)^2=x^2*A(n-1)^2+y^2*A(n-2)^2+2*x*y*A(n-1)*A(n-2);
也就是说S(n)=S(n-1)+A(n)^2=S(n-1)+x^2*A(n-1)^2+y^2*A(n-2)^2+2*x*y*A(n-1)*A(n-2);
我们从中取出不能直接求解的部分构成一个矩阵M={S(n-1),A(n-1)^2,A(n-2)^2,A(n-1)*A(n-2)}
然后由此可以看出有一个辅助矩阵D={1 0 0 0
x^2 x^2 1 x
y^2 y^2 0 0
2*x*y 2*x*y 0 y}
第一列是S(n)与S(n-1)的转化方程
第二列是A(n)^2与A(n-1)^2的转化方程
第三列是为了将A(n-2)变为A(n-1)
第四列:
x*A(n-1)^2+y*A(n-1)*A(n-2)=(x*A(n-1)+y*A(n-2))*A(n-1)=A(n)*A(n-1)
由此的我们可以很方便的从S(n-1)求解出S(n),只需要一个辅助矩阵
然后为了提高效率,可以采用二进制的思想(二进制思想具体参见北大程序设计引导及在线实践的P169)
本题要对最终结果模10007,所以为了防止溢出,我们可以在乘法后立即模10007,不会改变数值(模定理具体参见白书180)
贴出我自己的代码:
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <string>
using namespace std;
const int MOD = 10007;
long long int N, X, Y;
struct Matrix
{
int date[4][4];
void setE()
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
date[i][j] = (i == j);
}
}
}
void setO()
{
memset(date, 0, sizeof(date));
}
void print()
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
printf("%d ", date[i][j]);
}
cout << endl;
}
}
};
Matrix add(Matrix &a, Matrix &b)
{
Matrix e;
e.setO();
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
e.date[i][j] = (a.date[i][j] + b.date[i][j]) % MOD;
}
}
return e;
}
Matrix mul(Matrix &a, Matrix &b)
{
Matrix e;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
e.date[i][j] = 0;
for (int k = 0; k < 4; k++)
{
e.date[i][j] += a.date[i][k] * b.date[k][j] % MOD;
}
e.date[i][j] %= MOD;
}
}
return e;
}
Matrix quick_pow(Matrix mat, long long int n)
{
Matrix ans;
ans.setE();
while (n)
{
if (n & 1)
{
ans = mul(ans, mat);
}
mat = mul(mat, mat);
n >>= 1;
}
return ans;
}
Matrix init()
{
Matrix mat;
mat.date[0][0] = 1;
mat.date[0][1] = 0;
mat.date[0][2] = 0;
mat.date[0][3] = 0;
mat.date[1][0] = mat.date[1][1] = (X % MOD) * (X % MOD) % MOD;
mat.date[1][2] = 1;
mat.date[1][3] = X % MOD;
mat.date[2][0] = mat.date[2][1] = (Y % MOD) * (Y % MOD) % MOD;
mat.date[2][2] = 0;
mat.date[2][3] = 0;
mat.date[3][0] = mat.date[3][1] = 2 * (X % MOD) * (Y % MOD) % MOD;
mat.date[3][2] = 0;
mat.date[3][3] = Y % MOD;
return mat;
}
int main()
{
int T[4] = {2, 1, 1, 1};
while (scanf("%lld%lld%lld", &N, &X, &Y) != EOF)
{
Matrix A = init();
// A.print();
Matrix B = quick_pow(A, N - 1);
// B.print();
int ans = 0;
for (int i = 0; i < 4; i++)
{
ans += T[i] * B.date[i][0] % MOD;
}
printf("%d\n", ans % MOD);
}
// system("pause");
return 0;
}