51nod 1365 Fib(N) mod Fib(K) & 蓝桥杯 斐波那契(数论)

38 篇文章 0 订阅
12 篇文章 0 订阅

51nod 1365 Fib(N) mod Fib(K)

Description

Fib(N)表示斐波那契数列的第N项(F(0) = 0, F(1) = 1),给出N和K,求Fib(N) mod Fib(K)。由于结果太大,输出Mod 1000000007的结果。

Input

第1行:一个数T,表示后面用作输入测试的数的数量。(1 <= T <= 50000)
第2 - T + 1行:每行2个数N, K(1 <= N, K <= 10^18)

Output

共T行:对应Fib(N) mod Fib(K)的结果再Mod 1000000007。

Input示例

2
5 5
13 5

Output示例

0
3

解题思路

参考博客http://blog.csdn.net/acdreamers/article/details/21822165
主要是公式的推导,按照自己的理解整理一下
由于公式 F(m+n)=F(m+1)F(n)+F(m)F(n-1),
所以F(n)%F(k)=F(n-k+k)%F(k)=[F(n-k+1)F(k)+F(n-k)F(k-1)]%F(k)=F(n-k)F(k-1)%F(k)=……=F(n%k) F(k1)nk F ( k − 1 ) n k %F(k).
由于 F(n)2=(1)n+1+F(n1)F(n+1) F ( n ) 2 = ( − 1 ) n + 1 + F ( n − 1 ) F ( n + 1 ) ,
所以有 F(k1)2=(1)k+F(k1)F(k) F ( k − 1 ) 2 = ( − 1 ) k + F ( k − 1 ) F ( k ) F(k1)2 F ( k − 1 ) 2 % F(k)=(1)k F ( k ) = ( − 1 ) k .
令n%k=x, nk=y n k = y ,
则原式= [F(x)F(k1)y] [ F ( x ) F ( k − 1 ) y ] %F(k).
当k 为偶数时: F(k1)2 F ( k − 1 ) 2 %F(k)=1.
  则当y 为偶数时,原式=F(x)%F(k),
  当y 为奇数时,原式=[F(x)*F(k-1)]%F(k);
当k 为奇数时: F(k1)2 F ( k − 1 ) 2 %F(k)=-1.
  当y 为偶数时(代表y个F(k-1)可以两两凑成一对).
    当 y2 y 2 为偶数时(代表有偶数个-1相乘),则原式=F(x)%F(k),
    当 y2 y 2 为奇数时(代表最后会留下一个-1),则原式=[-F(x)]%F(k)=F(k)-F(x);
  当y 为奇数时(代表会留下一个F(k-1)无法配对).
    当 y2 y 2 为偶数时,原式=[F(x)F(k-1)]%F[k],
    当 y2 y 2 为奇数时,原式=[-F(x)F(k-1)]%F(k)=F(k)-F(x)F(k-1)%F(k);
接下来简化F(x)*F(k-1):
利用性质,当n>=1,r>=2,有F(n)F(n+r-1)-F(n+1)F(n+r-2)= (1)n+1F(r2) ( − 1 ) n + 1 F ( r − 2 ) ,
令x=n+1,k-1=n+r-2,则有F(x-1)F(k)-F(x)F(k-1)= (1)xF(kx) ( − 1 ) x F ( k − x ) ,
可转化为 F(x)F(k-1)-F(x-1)F(k)= (1)x+1F(kx) ( − 1 ) x + 1 F ( k − x ) ,
所以 F(x)F(k-1)%F(k)= (1)x+1F(kx) ( − 1 ) x + 1 F ( k − x ) .
则当x 为奇数时,原式=F(k-x),
当x 为偶数时,原式=[-F(k-x)]%F(k)=F(k)-F(k-x).
对于求斐波那契,使用矩阵快速幂来优化就可以了.

代码实现

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9+7;
#define IO ios::sync_with_stdio(false);\
cin.tie(0);\
cout.tie(0);
struct matrix{
    ll m[2][2];
}ans,base;
//矩阵相乘
matrix multi(matrix a,matrix b)
{
    matrix tmp;
    for(int i=0;i<2;i++)
    {
        for(int j=0;j<2;j++)
        {
            tmp.m[i][j]=0;
            for(int k=0;k<2;k++)
                tmp.m[i][j]=(tmp.m[i][j]+a.m[i][k]*b.m[k][j]%mod)%mod;
        }
    }
    return tmp;
}
//矩阵快速幂
ll getFib(ll n)
{
    base.m[0][0]=base.m[0][1]=base.m[1][0]=1;
    base.m[1][1]=0;
    ans.m[0][0]=ans.m[1][1]=1;
    ans.m[0][1]=ans.m[1][0]=0;
    while(n)
    {
        if(n&1)
            ans=multi(ans,base);
        base=multi(base,base);
        n/=2;
    }
    return ans.m[1][0]%mod;
}
//返回fib(n%k)*fib(k-1)%mod t=n%k,m=k-1
ll getmul(ll t,ll m)
{
    if(t%2==1)
        return getFib(m-t+1);
    else
        return ((getFib(m+1)-getFib(m-t+1))%mod+mod)%mod;
}
ll solve(ll n,ll k)
{
    ll x=n%k,y=n/k;
    if((k&1)==0)
    {
        if((y&1)==0)
            return getFib(x);
        else
            return getmul(x,k-1);
    }
    else
    {
        if((y&1)==0&&((y/2)&1)==0)
            return getFib(x);
        else if((y&1)==0&&((y/2)&1))
            return ((getFib(k)-getFib(x))%mod+mod)%mod;
        else if((y&1)&&((y/2)&1)==0)
            return getmul(x,k-1);
        else if((y&1)&&((y/2)&1))
            return ((getFib(k)-getmul(x,k-1))%mod+mod)%mod;
    }
}
int main()
{
    IO;
    int T;
    ll n,k;
    cin>>T;
    while(T--)
    {
        cin>>n>>k;
        cout<<solve(n,k)<<endl;
    }
    return 0;
}

蓝桥杯 斐波那契

问题描述

  斐波那契数列大家都非常熟悉。它的定义是:

  f(x) = 1 …. (x=1,2)
  f(x) = f(x-1) + f(x-2) …. (x>2)

  对于给定的整数 n 和 m,我们希望求出:
  f(1) + f(2) + … + f(n) 的值。但这个值可能非常大,所以我们把它对 f(m) 取模。
  公式如下
  这里写图片描述
  但这个数字依然很大,所以需要再对 p 求模。

输入格式

  输入为一行用空格分开的整数 n m p (0 < n, m, p < 10^18)

输出格式

  输出为1个整数,表示答案

样例输入

2 3 5
15 11 29

样例输出

0
25

解题思路

和上一题不同的是,这里是求和再取模,这个很容易解决,就是利用规律 ni=1f(i)=f(n+2) ∑ i = 1 n f ( i ) = f ( n + 2 ) .
另外还有一个问题就是这个取模的范围也是1e18,这就导致在矩阵相乘时可能出现1e18*1e18的情况,所以我们还是需要使用类似于矩阵快速幂的思想来解决这个问题,具体见代码.

代码实现

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IO ios::sync_with_stdio(false);\
cin.tie(0);\
cout.tie(0);
struct matrix
{
    ll m[2][2];
} ans,base;

ll mod;
ll mul(ll a ,ll b)
{
    a=(a%mod+mod)%mod;
    b=(b%mod+mod)%mod;
    if(a<b) swap(a,b);
    ll ans=0;
    while(b)
    {
        if(b&1) ans=(ans+a)%mod;
        a=(a*2)%mod;
        b/=2;
    }
    return ans;
}

matrix multi(matrix a,matrix b)
{
    matrix tmp;
    for(int i=0; i<2; i++)
    {
        for(int j=0; j<2; j++)
        {
            tmp.m[i][j]=0;
            for(int k=0; k<2; k++)
                tmp.m[i][j]=(tmp.m[i][j]+mul(a.m[i][k],b.m[k][j]))%mod;
        }
    }
    return tmp;
}
ll getFib(ll n)
{
    base.m[0][0]=base.m[0][1]=base.m[1][0]=1;
    base.m[1][1]=0;
    ans.m[0][0]=ans.m[1][1]=1;
    ans.m[0][1]=ans.m[1][0]=0;
    while(n)
    {
        if(n&1)
            ans=multi(ans,base);
        base=multi(base,base);
        n/=2;
    }
    return ans.m[0][1]%mod;
}
ll getmul(ll t,ll m)
{
    if(t%2==1)
        return getFib(m-t+1);
    else
        return ((getFib(m+1)-getFib(m-t+1))%mod+mod)%mod;
}
ll solve(ll n,ll k)
{
    ll x=n%k,y=n/k;
    if((k&1)==0)
    {
        if((y&1)==0)
            return getFib(x);
        else
            return getmul(x,k-1);
    }
    else
    {
        if((y&1)==0&&((y/2)&1)==0)
            return getFib(x);
        else if((y&1)==0&&((y/2)&1))
            return ((getFib(k)-getFib(x))%mod+mod)%mod;
        else if((y&1)&&((y/2)&1)==0)
            return getmul(x,k-1);
        else if((y&1)&&((y/2)&1))
            return ((getFib(k)-getmul(x,k-1))%mod+mod)%mod;
    }
}
int main()
{
    IO;
    ll n,k;
    cin>>n>>k>>mod;
    ll ans = solve(n+2,k);
    if(ans==0)
        cout<<getFib(k)-1<<endl;
    else
        cout<<ans-1<<endl;
    return 0;
}

PS:
1.为什么用类似mul()的方法处理F(x)*F(k-1)不行;
2.a%b%c (a%c)%b,(a*b)%c%d (a%d)*(a%d)%c,所以中间的取模处理是为什么;
3.性质:当n>=1,r>=2,有F(n)F(n+r-1)-F(n+1)F(n+r-2)= (1)n+1F(r2) ( − 1 ) n + 1 F ( r − 2 ) .

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值