hdu3221 09年上海赛区programB

解题报告

题目 http://acm.hdu.edu.cn/showproblem.php?pid=3221

(09年上海赛区programB)

题目大意 : f[n] = f[n – 1] * f[n – 2] f[1] = a; f[2] =b; f[n] % p;

算法 a ^ b % c = a ^(b % phi[c] + phi[c]) % c   (b >= phi[c])时, 矩阵快速幂

思路 f[n] = f[n – 1] * f[n – 2] f[n] = (a^x * b^y) % p; à f[n] = a^x % p * b^y %p %p

è 由乘法的结合率知xy是斐波纳妾的第ff[n – 2] ff[n – 1]项。

è F[n] = (a^ff[n – 2] % p ) * ( b^ff[n – 1] % p) % p

è F[n] = (a^( ff[n – 2] % phi[p] + phi[p]) % p) *  b^( ff[n – 1] % phi[p] + phi[p]) % p) % p )

è 解次表达式即可,其中斐波纳妾数列ff要用矩阵快速幂求

è 要注意的是公式当(b >= phi[c])时才能用,应此前50项左右要用朴素算法。

一直wan=1的时候,n=1时输出a%p而不是a

收获与总结 :再次感受了数论的魅力,太爽了!细心啊。

提交情况 wrong answer 6 (第一项出错了)

                      Accepted 1

AC code

#include <stdio.h>

#include <math.h>

#include <string.h>

 

typedef __int64 I64;

I64 a, b, n, p, q1, q2;

 

struct LINE{

    I64 line[2];

};

 

struct ROW{

    LINE row[2];

};

 

I64 Multi(I64 aa, I64 bb, I64 cc){

    I64 ans = 0;

    while(bb){

       if(bb & 1) ans = (ans + aa) % cc;

       aa = (aa + aa) % cc;

       bb >>= 1;

    }

    return ans;

}

 

I64 MOD(I64 aa, I64 bb, I64 cc){

    I64 ans = 1;

    while(bb){

       if(bb & 1) ans = Multi(ans, aa, cc);

       aa = Multi(aa, aa, cc);

       bb >>= 1;

    }

    return ans;

}

 

I64 Getphi(I64 c){

    I64 ans = c, i, m;

    if(c % 2 == 0){

       ans = ans / 2;

       while(c % 2 == 0) c /= 2;

    }

    m = (I64)sqrt((long double)c) + 1;

    for(i = 3; i <= m && c >= i; i += 2){

       if(c % i) continue;

       ans = (ans / i) * (i - 1);

       while(c % i == 0) c /= i;

    }

    if(c != 1) ans = (ans / c) * (c - 1);

    return ans;

}

 

ROW Matrix_Multi(ROW A, ROW B, I64 phip){

    int i, j , k;

    ROW ans = {0};

    for(i = 0; i < 2; i ++)

       for(j = 0; j < 2; j ++)

           for(k = 0; k < 2; k ++)

              ans.row[i].line[j] = (ans.row[i].line[j] + Multi(A.row[i].line[k], B.row[k].line[j], phip)) % phip;

    return ans;

}

          

voidget_F_mod_phi(int m, int phip){

    ROW A, temp;

    A.row[0].line[0] = 0; A.row[0].line[1] = 1;

    A.row[1].line[0] = 1; A.row[1].line[1] = 1;

    temp.row[0].line[0] = 1; temp.row[0].line[1] = 0;

    temp.row[1].line[0] = 0; temp.row[1].line[1] = 1;

    while(m){

       if(m & 1) temp = Matrix_Multi(temp, A, phip);

       A = Matrix_Multi(A, A, phip);

       m >>= 1;

    }

    q1 = (temp.row[0].line[0] + temp.row[1].line[0]) % phip;

    q2 = (temp.row[0].line[1] + temp.row[1].line[1]) % phip;

}

 

I64 get(){

    I64 f[100], ans;

    int i;

    if(n == 1) return a % p;

    if(n == 2) return b % p;

    f[1] = f[2] = 1;

    for(i = 3; i < n; i ++) f[i] = f[i - 1] + f[i - 2];

    ans = Multi(MOD(a, f[n - 2], p), MOD(b, f[n - 1], p), p);

    return ans;

}

 

I64 chap(){

    I64 phip;

    phip = Getphi(p);

    get_F_mod_phi(n - 3, phip);

    I64 ans1 = MOD(a, q1 + phip, p);

    I64 ans2 = MOD(b, q2 + phip, p);

    return Multi(ans1, ans2, p);

}

 

int main(){

    int CASE, T;

    I64 ans;

    scanf("%d", &CASE);

    for(T = 1; T <= CASE; T ++){

       scanf("%I64d %I64d %I64d %I64d", &a, &b, &p, &n);

       ans = n > 50 ? chap() : get();

       printf("Case #%d: %I64d\n", T, ans);

    }

    return 0;

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值