又见斐波那契数列
远航学长出的题,确实不错。运用到了矩阵快速幂和快速幂取模以及很关键的费马小定理。
题意:
F[0] = a
F[1] = b
F[n] = F[n-1] * F[n-2] ( n > 1 )
现在给出a,b,n;求第n项对1e9+7取模的值。
先来普及一下费马小定理吧:信息安全的专业的大二会学信息安全数学基础,纯数论。其中就有提到费马小定理。
其实也就一句话:设p是一个素数,对于任意整数a,有:(a^p)%p=a%p,即(a^(p-1))%p=1%p,而1e9+7正好为素数。
有了这个就很好做了;题目已经知道了前两项,那么以后每一项都可以用a和b的指数形式给出。枚举前几项可以发现其指数符合斐波那契数列的,且a的指数与b的指数正好相差一项。所以可以用矩阵快速幂求出a的指数与b的指数对1e9+6取模,再用快速幂对1e9+7取模即得最终结果。
4ms过了,我相信是后台水。
const ll MOD=1e9+7;
const ll mod=1e9+6;
ll x,y,n;
struct mat
{
ll a[2][2];//注意数据范围;
};
ll fast_pow(ll aa,ll bb)//快速幂
{
ll x=1;
aa%=MOD;
while(bb)
{
if(bb&1) x=(x*aa)%MOD;
aa=(aa*aa)%MOD;
bb=bb>>1;
}
return x;
}
mat mat_mul(mat x,mat y)//矩阵乘法
{
mat res;
memset(res.a,0,sizeof(res.a));
for(int i=0; i<2; i++)
for(int j=0; j<2; j++)
for(int k=0; k<2; k++)
res.a[i][j]=(res.a[i][j]+x.a[i][k]*y.a[k][j])%mod;//费马小定理;
return res;
}
void mat_fast_pow(int n)
{
mat c,res;
c.a[0][0]=c.a[0][1]=c.a[1][0]=1;
c.a[1][1]=0;
memset(res.a,0,sizeof(res.a));
for(int i=0; i<2; i++)
res.a[i][i]=1;
while(n)
{
if(n&1) res=mat_mul(res,c);
c=mat_mul(c,c);
n=n>>1;
}
ll yy=res.a[0][0],xx=res.a[0][1];//分别得到x和y的指数;
ll ans=(fast_pow(x,xx)*fast_pow(y,yy))%MOD;//快速幂取模
printf("%I64d\n",ans);
}
int main()
{
while(~scanf("%I64d%I64d%I64d",&x,&y,&n))
{
x%=MOD;
y%=MOD;
if(n==0)
{
printf("%I64d\n",x);
continue;
}
mat_fast_pow(n-1);
}
return 0;
}
知识结合性很好,思路很好得出,但前提是这些知识点熟练运用。