NYOJ-1000 又见斐波那契数列

        

又见斐波那契数列

       远航学长出的题,确实不错。运用到了矩阵快速幂和快速幂取模以及很关键的费马小定理。

     题意:

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;
}

知识结合性很好,思路很好得出,但前提是这些知识点熟练运用。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值