蓝桥杯试题 算法训练 小X的暑假作业
题目描述:
资源限制
时间限制:1.0s 内存限制:128.0MB
问题描述
小X的作业是老师给他布置的,题目很简单,求出第N个斐波那契数 mod P的值。小X怎么想也想也想不出来,只好求助于你了。
输入格式
第一行为数据组数T。
第二行开始,以下T行,每行为老师给小X布置的作业中的N和P。
输出格式
包含T行,每行是一个作业的答案。
样例输入
3
7 3
1000000 89
987654321 30000
样例输出
0
55
19111
数据规模和约定
对于50%的数据,T<=100,N<=10000。
对于100%的数据,T<=10000,N<=1000000000,P<=30000。
斐波那契数的第0个是1。
(可以看到n的值这么大,肯定不能直接用斐波那契的式子)
解题思路:
1 1 2 3 5 8(其中,第一个1是第0项,也就是从第0项开始的斐波那契数列),
目的:求第n项的数值。【这里先忽略取模,暂时讲一下大致思路,不影响,写代码的时候加上取模即可】
我们设第n项为F(n)。
由斐波那契的数列性质可以知道,F(n)=F(n-1)+F(n-2)----------------①
而F(n-1)=F(n-1)+0*F(n-2)------------------②【这一步可能会不知道为什么,先往下看,只是为了凑出矩阵A】
由①②两个式子综合可得:
F(n)=F(n-1)+F(n-2)
F(n-1)=F(n-1)+0*F(n-2)
可以推出:一个和矩阵相关的式子(下面)图片有点丑,莫嫌弃,哈哈哈
然后可以推出,下面这个式子:
所以F(n)的值就等于矩阵A{1,1,1,0}的n-1次方,乘以{F(1),F(0)},而F(1),F(0)都为1,所以,F(n)的值就等于矩阵A{1,1,1,0}的n-1次方(这里叫做矩阵B),矩阵B的第一行的和(B[0][0]+B[0][1])
所以我们的目标就是算出来A{1,1,1,0}的n-1次方即可,由于n很大很大,就用快速幂的方法做。
快速幂是专门解决a的b次方然后对一个数取模的,只不过这里的a不是一个数值,而是一个确定的矩阵。
AC代码:
#include <stdlib.h>
#include <stdio.h>
#include <algorithm>
#include <iostream>
#include <string.h>
#include <math.h>
using namespace std;
long long tt[2][2];
int n,p;
void f(long long a[2][2],long long b[2][2])//计算a矩阵乘以b矩阵的值
{
long long temp[2][2];
int i,j,k;
memset(temp,0,sizeof(temp));
for(i=0;i<2;i++)
for(j=0;j<2;j++)
for(k=0;k<2;k++)
temp[i][j]+=a[i][k]*b[k][j];
for(i=0;i<2;i++)
for(j=0;j<2;j++)
tt[i][j]=temp[i][j]%p;//拷贝到tt数组中
}
int main()
{
int t;
cin>>t;
while(t--)
{
long long t,a[2][2]={1,1,1,0},ans[2][2]={1,0,0,1},temp[2][2];
memset(temp,0,sizeof(temp));
cin>>n>>p;
n--;
while(n)
{
if(n&1)
{
f(ans,a);//注意ans初始值为单位矩阵
memcpy(ans,tt,sizeof(tt));
}
f(a,a);
memcpy(a,tt,sizeof(tt));
n>>=1;//右移一位
}
cout<<(ans[0][0]+ans[0][1])%p<<endl;//乘以初始矩阵B(b矩阵上面有说明)
}
return 0;
}