您的位置:首页 > 其它

【矩阵乘法】【codevs 1250】Fibonacci数列

2015-06-03 21:36 399 查看

1250 Fibonacci数列

[code] 时间限制: 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

[code]第一行一个数T(1<=T<=10000)。
以下T行,每行两个数,n,q(n<=10^9, 1<=q<=30000)


输出描述 Output Description

[code]文件包含T行,每行对应一个答案。


样例输入 Sample Input

[code]3
6 2
7 3
7 11


样例输出 Sample Output

[code]1
0
10


数据范围及提示 Data Size & Hint

[code]1<=T<=10000
n<=10^9, 1<=q<=30000


题解:

因为n是10^9,所以不能用朴素的O(n)的地推来解决,我们需要具有更加优秀复杂度的算法——矩阵乘来帮助。

先简单介绍一下它:

矩阵乘是O(logn)的复杂度,针对的对象是一个n行m列和一个m行p列的矩阵。矩阵乘所得到的就是一个n行p列的矩阵,这个矩阵的第i行第j列是由一个矩阵的第i行的每一个数与另一个矩阵的第j列的对应数乘积的加和。一般的情况下,我们可以用快速幂来进行加速。

朴素的矩阵乘:

[code]for (int i=1; i<=n; i++)
        for (int j=1; j<=p; j++)
            for (int k=1; k<=m; k++)
                c[i][j]+=a[i][k]*b[k][j];


回归问题,我们需要求的是Fibonacci数列的第n项,可以建立两个矩阵:




然后让它们两个相乘,我们可以得到这样的矩阵:




于是我们可以发现,对于f
而言,它实际上可以由这样两个矩阵转移来,而对于B矩阵,它也是由上一层转移来的,所以对于f
来说,它可以这样得到:




于是可以应用快速幂加速下的矩阵乘来解决。(传参时各种奇怪问题希望大家小心一下。。。)

Code:

[code]#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int T,n,q,ans,a[2][2],b[2][2];
int in(){
    int x=0; char ch=getchar();
    while (ch<'0' || ch>'9') ch=getchar();
    while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return x;
}
void init(){
    a[0][0]=a[0][1]=a[1][0]=1; a[1][1]=0;
    b[0][0]=b[0][1]=b[1][0]=1; b[1][1]=0;
}
void matrix(int x[2][2],int y[2][2]){
    int c[2][2]={0};
    for (int i=0; i<=1; i++)
        for (int j=0; j<=1; j++)
            for (int k=0; k<=1; k++)
                c[i][j]=(c[i][j]+x[i][k]*y[k][j])%q;
    for (int i=0; i<=1; i++)
        for (int j=0; j<=1; j++)
            y[i][j]=c[i][j];
}
int main(){
    T=in();
    while (T--){
        n=in(),q=in();
        init();
        if (n<=1){
            printf("1\n");
            continue;
        }
        int y=n-2;
        while (y){
            if (y&1) matrix(a,b);
            y>>=1; matrix(a,a);
        }
        ans=(b[0][0]+b[0][1])%q;
        printf("%d\n",ans);
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: