递推求值
时间限制:1000 ms | 内存限制:65535 KB
难度:4
描述
给你一个递推公式:
f(x)=a*f(x-2)+b*f(x-1)+c
并给你f(1),f(2)的值,请求出f(n)的值,由于f(n)的值可能过大,求出f(n)对1000007取模后的值。
注意:-1对3取模后等于2
输入
第一行是一个整数T,表示测试数据的组数(T<=10000)
随后每行有六个整数,分别表示f(1),f(2),a,b,c,n的值。
其中0<=f(1),f(2)<100,-100<=a,b,c<=100,1<=n<=100000000 (10^9)
输出
输出f(n)对1000007取模后的值
样例输入
2
1 1 1 1 0 5
1 1 -1 -10 -100 3
样例输出
5
999896
分析:由于n的值比较大,所以常规方法肯定会超时。根据递推式求第n个表达式的值时,通常用矩阵乘法来做。
本题要构造两个矩阵,其中一个为矩阵A,作为初始矩阵
f2 0 0
f1 0 0
1 0 0
另一个为矩阵B
b a c
1 0 0
0 0 1
另一个为单位矩阵C【用来与B进行快速幂】
1 0 0
0 1 0
0 0 1
因为F(2)和F(1)是已知的,当n>=3时,每次都乘以矩阵B,
就能推出下一个矩阵。而矩阵的第一行第一列的元素就是所求的结果。
所以利用矩阵快速幂能够快速准确地求出结果。
#include<stdio.h>
#include<string.h>
#define mod 1000007
#define N 3
typedef long long LL;
struct Matrix
{
LL mat[N][N];
};
Matrix unit_matrix =
{
1, 0, 0,
0, 1, 0,
0, 0, 1
}; //单位矩阵
Matrix mul(Matrix a, Matrix b) //矩阵相乘
{
Matrix res;//res=A*B 结果中转站
for(int i = 0; i < N; i++)
for(int j = 0; j < N; j++)
{
res.mat[i][j] = 0;
for(int k = 0; k < N; k++)
{
res.mat[i][j] += a.mat[i][k] * b.mat[k][j];
res.mat[i][j] %= mod;
}
}
return res;
}
Matrix pow_matrix(Matrix a, LL n) //矩阵快速幂
{
Matrix res = unit_matrix;//用单位矩阵进行快速幂
while(n != 0)
{
if(n & 1)
res = mul(res, a);
a = mul(a, a);
n >>= 1;
}
return res;
}
int main()
{
LL n, f1, f2, a, b, c, T;
Matrix tmp, arr;
scanf("%lld",&T);
while(T--)
{
scanf("%lld%lld%lld%lld%lld%lld",&f1, &f2, &a, &b, &c, &n);
if(n == 0)
printf("%lld\n",(f2-f1*b-c + mod)%mod);
if(n == 1)
printf("%lld\n",(f1+mod)%mod);
else if(n == 2)
printf("%lld\n",(f2+mod)%mod);
else
{
memset(arr.mat, 0, sizeof(arr.mat));//Fn矩阵
memset(tmp.mat,0,sizeof tmp.mat);
arr.mat[0][0] = f2; arr.mat[1][0] = f1; arr.mat[2][0] = 1;//初始化
tmp.mat[0][0] = b; tmp.mat[0][1] = a; tmp.mat[0][2] = c;//快速幂系数矩阵
tmp.mat[1][0] = tmp.mat[2][2] = 1;
//tmp.mat[1][1] = tmp.mat[1][2] = tmp.mat[2][0] = tmp.mat[2][1] = 0;
Matrix p = pow_matrix(tmp, n-2);//快速幂结果
p = mul(p, arr);//最后,矩阵相乘
LL ans = (p.mat[0][0] + mod) % mod;
printf("%lld\n",ans);
}
}
return 0;
}