向前走莫回头❤

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

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;
}
posted @ 2016-05-22 20:21  lris0-0  阅读(1112)  评论(0编辑  收藏  举报
过去的终会化为美满的财富~o( =∩ω∩= )m