2013 Asia Regional Contest C题 解题报告

本文介绍了一种特殊的Fibonacci数列计算方法,通过矩阵乘法和数论技巧解决多组测试数据的问题,并给出了快速幂算法实现步骤。

链接:

Description:

定义一种新型的Fibonacii 数列:

F[0] = a

F[1] = b

F[i] = F[i-1] * F[i-2] (n > 1)

请根据给出的abn,求出F[n]的大小。

Input:

多组测试数据,处理到文件结束,对于每组测试数据:

输入三个整数abn0a,b,n10^9

Output:

对于每组测试数据输出F[n]1000000007取模后的结果,每组输出占一行;


分析:

矩阵乘法+数论

因为F[n] = F[n-1] * F[n-2]

设f(0) = 0, f(1) = 1, f(n) = f(n-1) + f(n-2) (n>=2)

那么有 F(n) = a^f(n) * b^f(n+1)

根据费马小定理,1000000007是一个素数,那么所求可以简化成 a^(f(n)%1000000006) * b^(f(n+1)%1000000006)

所以我们可以先求f(n)%1000000006和f(n+1)%1000000006 , 可用快速幂来求得;

同样再用快速幂求的 a^(f(n)%1000000006) 和 b^(f(n+1)%1000000006)即可;

解题代码如下:
#include <cstdio>
#include <cstring>
#include <ctime>
#include <algorithm>
using namespace std;
const long long mod = 1000000007;
const long long mod2 = 1000000006;

void mul(long long a[][2], long long b[][2], long long m){
    long long c[2][2];
    int i, j, k;
    for (i=0; i<2; i++){
        for (j=0; j<2; j++){
            c[i][j] = 0;
            for (k=0; k<2; k++){
                c[i][j] +=  (a[i][k] * b[k][j])%m;
            }
        }
    }
    for (i=0; i<2; i++)
        for (j=0; j<2; j++){
            b[i][j] = c[i][j]%m;
        }
}


long long cal(long long n){
    long long e[2][2], r[2][2];
    e[0][0] = e[0][1] = e[1][0] = 1; e[1][1] = 0;
    r[0][0] = 1; r[1][0] = 0;
    n--;

    while (n){
        if (n%2==1)
            mul(e, r, mod2);
        mul(e, e, mod2);
        n = n/2;
    }

    return r[0][0];
}

long long solve(long long a, long long b){
    long long res = 1;
    while (b){
        if (b%2==1)
            res = (res * a)%mod;
        a = (a*a)%mod;
        b /= 2;
    }
    return res;
}

int main(){
    long long a, b, n;
    long long k1, k2, res;
    while (scanf("%lld %lld %lld",&a,&b,&n)!=EOF){
        if (n==0){ printf("%lld\n",a%mod); continue;}
        if (n==1){ printf("%lld\n",b%mod); continue;}
        if (n==2){ printf("%lld\n",(a*b)%mod); continue;}

        k1 = cal(n-1);
        k2 = cal(n);
        k1 = solve(a, k1);
        k2 = solve(b, k2);
        printf("%lld\n",(k1*k2)%mod);
    }
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值