矩阵快速幂-GCD-斐波那契-HZAU2017现场赛-D

来源:互联网 发布:网络连环夺宝 编辑:程序博客网 时间:2024/05/16 12:56

题目链接

http://acm.hzau.edu.cn/problem.php?id=1202

题意

有T组样例,每组样例给你n,m,p三个数。(1<=n,m,p<=10^9)对于每组样例让你输出gcd(1+Sn,1+Sm)%p,其中Sn是斐波那契数列的前n项和。

题解

这题我觉得主要就是几个结论,还是有必要记得。

结论一: 对于斐波那契数列fi(n),1+Sn = fi(n+2)
证明: 1+Sn = 1+S(n-2)+fi(n+1) = 1+S(n-4)+fi(n-1)+fi(n+1) = 1+S(2)+fi(5)+…+fi(n+1) = 1+fi(3)+fi(5)+…+fi(n+1) = fi(2)+fi(3)+fi(5)+…+fi(n+1) = fi(n)+fi(n+1) = fi(n+2)

结论二: gcd(fi(n),fi(m)) = fi(gcd(n,m))
证明:很复杂,有兴趣的看一看,没兴趣的记结论就行了。
这里写图片描述

如果还有兴趣知道斐波那契数列的其它性质,可以下载我上传的这个资料:
http://download.csdn.net/detail/williamsun0122/9828362

最主要的其实就是知道上述两个性质,然后构造出矩阵就可以了。我构造的矩阵如下:

[fi(n)0fi(n1)0]=[fi(n1)0fi(n2)0][1110]

因为数很大,矩阵乘法中可能爆int,所以用long long。

#include <bits/stdc++.h>using namespace std;typedef long long ll;ll n,m,p,x;ll a[2][2],b[2][2],ans[2][2],tmp[2][2];int gcd(ll a,ll b){    return b==0 ? a:gcd(b,a%b);}void multi(ll sz1[][2],ll sz2[][2]){    memset(tmp,0,sizeof(tmp));    for(int i=0;i<2;i++)    {        for(int k=0;k<2;k++)        {            for(int j=0;j<2;j++)            {                tmp[i][j] += sz1[i][k]*sz2[k][j];                tmp[i][j] %= p;            }        }    }    for(int i=0;i<2;i++)    {        for(int j=0;j<2;j++)        {            sz1[i][j]=tmp[i][j];        }    }}void pow_mod(){    ans[0][0]=1,ans[0][1]=0,ans[1][0]=0,ans[1][1]=1;    b[0][0]=1,b[0][1]=1,b[1][0]=1,b[1][1]=0;    while(x)    {        if(x&1) multi(ans,b);        x >>= 1;        multi(b,b);    }}int main(){    //freopen("std.in","r",stdin);    //freopen("out.txt","w",stdout);    int T;    scanf("%d",&T);    while(T--)    {        scanf("%lld%lld%lld",&n,&m,&p);        x = gcd(n+2,m+2);        //cout<<"gcd="<<x<<endl;        if(x>2)        {            x -= 2;            pow_mod();            a[0][0]=1,a[0][1]=1,a[1][0]=0,a[1][1]=0;            multi(a,ans);            printf("%lld\n",a[0][0]);            continue;        }        else        {            printf("1\n");            continue;        }    }    return 0;}
0 0
原创粉丝点击