【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;
}
既然无能更改,又何必枉自寻烦忧