题目:http://acm.nyist.net/JudgeOnline/problem.php?pid=301
题意:给你一个递推公式:f(n)=a*f(n-2)+b*f(n-1)+c 并且告诉你a,b,c,f(1),f(2)和n的值,求出f(n)%1000007。其中0<f(1),f(2)<100,-100≤a,b,c≤100,1≤n≤10^9。注意取模后的结果不能为负数。
分析:直接递推求值会超时。可以转化成矩阵相乘
b 1 0
[F(n) F(n-1) c]=[F(n-1) F(n-2) c] * a 0 0
1 0 1
b 1 0
根据矩阵的结合律,可以先求出 a 0 0 的p次幂(矩阵快速幂),再乘上一个[F(2) F(1) c]。
1 0 1
代码:
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long LL;
const LL MOD=1000007LL;
struct Matrax
{
LL mat[3][3];
}ans,F,U;
LL a,b;
Matrax multi(Matrax a,Matrax b)
{
Matrax ret;
int i,j,k;
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
{
ret.mat[i][j]=0;
for(k=0;k<3;k++)
ret.mat[i][j]+=a.mat[i][k]*b.mat[k][j];
if(ret.mat[i][j]>=MOD || ret.mat[i][j]<=-MOD)
ret.mat[i][j]%=MOD;
if(ret.mat[i][j]<0)
ret.mat[i][j]+=MOD;
}
}
return ret;
}
Matrax solve(LL n)
{
Matrax ret=U,p=F;
while(n)
{
if(n&1)
ret=multi(ret,p);
n>>=1;
p=multi(p,p);
}
return ret;
}
void init()
{
F.mat[0][0]=b%MOD;
F.mat[0][1]=1;
F.mat[0][2]=0;
F.mat[1][0]=a%MOD;
F.mat[1][1]=0;
F.mat[1][2]=0;
F.mat[2][0]=1;
F.mat[2][1]=0;
F.mat[2][2]=1;
}
int main()
{
U.mat[0][0]=1;
U.mat[0][1]=0;
U.mat[0][2]=0;
U.mat[1][0]=0;
U.mat[1][1]=1;
U.mat[1][2]=0;
U.mat[2][0]=0;
U.mat[2][1]=0;
U.mat[2][2]=1;
LL n;
int ncase;
scanf("%d",&ncase);
while(ncase--)
{
scanf("%lld%lld%lld%lld%lld%lld",&ans.mat[0][1],&ans.mat[0][0],&a,&b,&ans.mat[0][2],&n);//f1,f2
if(n==1)
{
printf("%lld\n",ans.mat[0][1]%MOD);
continue;
}
else if(n==2)
{
printf("%lld\n",ans.mat[0][0]%MOD);
continue;
}
n-=2;
init();
Matrax ret=solve(n);
ans.mat[0][0]=ret.mat[0][0]*ans.mat[0][0]+ret.mat[1][0]*ans.mat[0][1]+ret.mat[2][0]*ans.mat[0][2];
ans.mat[0][0]%=MOD;
if(ans.mat[0][0]<0)
ans.mat[0][0]+=MOD;
printf("%lld\n",ans.mat[0][0]);
}
return 0;
}