您的位置:首页 > 其它

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

2017-04-28 12:41 435 查看

题目链接

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(n−1)0]=[fi(n−1)0fi(n−2)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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: