【codevs 1250】Fibonacci数列(矩阵快速幂)

来源:互联网 发布:圣思园java视频百度云 编辑:程序博客网 时间:2024/06/09 17:12

1250 Fibonacci数列
时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond
题目描述 Description
定义:f0=f1=1, fn=fn-1+fn-2(n>=2)。{fi}称为Fibonacci数列。
输入n,求fn mod q。其中1<=q<=30000。

输入描述 Input Description
第一行一个数T(1<=T<=10000)。以下T行,每行两个数,n,q(n<=109, 1<=q<=30000)

输出描述 Output Description
文件包含T行,每行对应一个答案。

样例输入 Sample Input
3
6 2
7 3
7 11

样例输出 Sample Output
1
0
10

数据范围及提示 Data Size & Hint
1<=T<=10000,n<=109, 1<=q<=30000
【用矩阵来求Fibonacci数列,首先构造一个初始矩阵:{1,1}({fn,fn-1}),和一个转移矩阵:{1,1}
{1,0} ,然后用两个相乘得到下一个数:{fn+1,fn},不停往后转移。也就相当于用初始矩阵乘n-1次转移矩阵,因为矩阵满足结合律,所以先将转移矩阵做快速幂,再与初始矩阵相乘】

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;struct unite{long long k[2][2];}d;//因为要加快速幂,所以转移矩阵用结构体来存储(不要在结构体里赋初值) long long f[2],d1[2]={0,0};int n,p,t;inline unite jc(unite a,unite b){ int i,j,l; unite c; c.k[0][0]=c.k[0][1]=c.k[1][0]=c.k[1][1]=0; for (i=0;i<=1;++i)  for (j=0;j<=1;++j)   for (l=0;l<=1;++l)    c.k[i][j]+=(a.k[i][l]*b.k[l][j])%p;return c;}//矩乘 inline unite poww(unite d,int q){ if (q==1) return d; if (q==2) return jc(d,d); if (q%2==0)  {   unite a;   a=poww(d,q/2);   a=jc(a,a);   return a;  }if (q%2==1) {  unite a;  a=poww(d,q/2);  a=jc(a,a);  a=jc(a,d);  return a; }}//快速幂inline void do1(int n){ d.k[0][0]=1; d.k[0][1]=1; d.k[1][0]=1; d.k[1][1]=0; d=poww(d,n); for (int j=0;j<=1;++j)  for (int l=0;l<=1;++l)    d1[j]+=f[l]*d.k[l][j];//将进行完快速幂的转移矩阵与原始矩阵相乘  printf("%lld\n",d1[0]%p); return;}int main(){ int i; scanf("%d",&t); for (i=1;i<=t;i++)  {   f[0]=1; f[1]=1;   memset(d1,0,sizeof(d1));   scanf("%d%d",&n,&p);   do1(n-1);  }//多组数据,每次做之前初始化  return 0;}
0 0
原创粉丝点击