NYOJ 1000
Posted 逸阳
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NYOJ 1000相关的知识,希望对你有一定的参考价值。
整体的思路是“快速幂取模算法”和“矩阵快速幂算法”的结合
F[0] = a1b0
F[1] = a0b1
F[2] = a1b1
F[3] = a1b2
F[4] = a2b3
F[5] = a3b5
F[6] = a5b8
...
观察可知F[n] = af(n-2)·bf(n-1)其中f(n-1)、f(n-2)是斐波那契数列,设p=1000000007(经检验可知p是质数,这引导我们中间计算矩阵幂时可用费马小定理)
故问题可转化为求 af(n-2)·bf(n-1)%p,即 (af(n-2)%p)·(bf(n-1)%p)%p. 接下来用快速幂取模算法解决,详见 http://www.cnblogs.com/liugl7/p/4831030.html
在使用快速幂取模算法之前需要解决的问题是快速计算斐波那契数列的值的问题,传统的迭代算法并不能满足快速计算的需求,所以这里使用矩阵快速幂算法。
令:
则易得 Mn = M0Fn (n>=1)
所以只需要计算出Fn然后乘上M0即可得到Mn, 然后就可以得到f(n-1),f(n-2)代入 (af(n-2)%p)·(bf(n-1)%p)%p 的计算。
代码如下:
1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 typedef long long LL; 5 #define MOD 1000000007 6 7 struct Matrax { //定义2*2的矩阵 8 LL mat[2][2]; 9 }U,F; 10 11 //2*2的两矩阵的乘法 12 Matrax multi(Matrax a,Matrax b) { 13 Matrax ans; 14 int i,j,k; 15 for(i=0;i<2;i++) { 16 for(j=0;j<2;j++) { 17 ans.mat[i][j]=0; 18 for(k=0;k<2;k++) 19 ans.mat[i][j]=(ans.mat[i][j]+(a.mat[i][k]%(MOD-1))*(b.mat[k][j]%(MOD-1)))%(MOD-1); 20 } 21 } 22 return ans; 23 } 24 25 //实现矩阵p的n次方 26 Matrax my_pow_matrax(int n) { 27 Matrax p=F,ans=U; 28 while(n) { 29 if(n&1) ans=multi(ans,p); 30 31 n>>=1; 32 p=multi(p,p); 33 } 34 return ans; 35 } 36 37 //初始化矩阵U=[1,0;0,1],即二阶单位矩阵; F=[1,1;1,0] 38 void Init() { 39 U.mat[0][0]=U.mat[1][1]=1; 40 U.mat[0][1]=U.mat[1][0]=0; 41 F.mat[0][0]=F.mat[0][1]=F.mat[1][0]=1; 42 F.mat[1][1]=0; 43 } 44 45 //快速幂取模算法,可用来得到 a^f(n-2)%p 和 b^f(n-1)%p 46 LL my_pow_ll(LL a,LL n) { 47 LL ans=1ll,p=a; 48 while(n) { 49 if(n&1) 50 ans=((ans%MOD)*(p%MOD))%MOD; 51 n>>=1; 52 p=((p%MOD)*(p%MOD))%MOD; 53 } 54 return ans; 55 } 56 57 int main() { 58 Init(); 59 LL a,b,n; 60 while(scanf("%lld%lld%lld",&a,&b,&n)!=EOF) { 61 if(n==0) { 62 printf("%lld\\n",a%MOD); 63 continue; 64 } 65 else if(n==1) { 66 printf("%lld\\n",b%MOD); 67 continue; 68 } 69 else if(n==2) { 70 printf("%lld\\n",a*b%MOD); 71 continue; 72 } 73 else { 74 Matrax temp=my_pow_matrax(n-1); 75 LL f1=temp.mat[0][0]*1+temp.mat[1][0]*0; // fib(n-1) 76 LL f2=temp.mat[0][1]*1+temp.mat[1][1]*0; // fib(n-2) 77 LL ans=(my_pow_ll(a,f2)%MOD)*(my_pow_ll(b,f1)%MOD)%MOD; 78 printf("%lld\\n",ans); 79 } 80 } 81 82 return 0; 83 }
以上是关于NYOJ 1000的主要内容,如果未能解决你的问题,请参考以下文章