(矩阵快速幂)解所有类似Fibonacci 的题目

版权声明:欢迎转载 https://blog.csdn.net/qq_40828914/article/details/81807804

Description

In the Fibonacci integer sequence, F0 = 0, F1 = 1, and Fn = Fn − 1 + Fn − 2 for n ≥ 2. For example, the first ten terms of the Fibonacci sequence are:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, …

An alternative formula for the Fibonacci sequence is

这里写图片描述
Given an integer n, your goal is to compute the last 4 digits of Fn.

Input

The input test file will contain multiple test cases. Each test case consists of a single line containing n (where 0 ≤ n ≤ 1,000,000,000). The end-of-file is denoted by a single line containing the number −1.

Output

For each test case, print the last four digits of Fn. If the last four digits of Fn are all zeros, print ‘0’; otherwise, omit any leading zeros (i.e., print Fn mod 10000).

Sample Input

0
9
999999999
1000000000
-1
Sample Output

0
34
626
6875

这个题是出题人好心,直接把规律给我们找出来了,那我们就只需要求那个矩阵的n次方,然后输出a[0][1]即可

1.先说说矩阵快速幂
为了类比快速幂,我们先写出快速幂的代码
快速幂求x的y次方,是把y看作二进制来的,矩阵快速幂也一样。
区别:
1.矩阵快速幂底数是矩阵,ren是矩阵
2.最终矩阵乘矩阵还是矩阵,也就是说函数返回矩阵,ans是矩阵
3.我们存答案的ans初始化应该是初等矩阵
所以涉及到矩阵的代码我们都要改

int pow_1(int x,int y){//x的y次方 
    int ren=x;
    int ans=1;
    while(y){
        if(y&1) ans*=ren;//取当前最末位的y,如果是1就继续乘ren 
        ren*=ren;//下一位ren是当前ren的平方 1 2 4 8,这里8是x^4的平方,不是4的平方 
        y=y>>1;//y前进一位 
    }
    return ans;
} 

改完之后就是这样了

struct matrix
{
    LL x[2][2];
};
matrix mutimatrix(matrix a,matrix b)
{
    matrix temp; 
    memset(temp.x,0,sizeof(temp.x));    
    for(int i=0;i<2;i++)
    for(int j=0;j<2;j++)
    for(int k=0;k<2;k++)
    {
        temp.x[i][j]+=a.x[i][k]*b.x[k][j];
        temp.x[i][j]%=mod;
    }
    return temp;
}

matrix k_powmatrix(matrix a,LL n)
{
    matrix temp;
    memset(temp.x,0,sizeof(temp.x));
    for(int i=0;i<2;i++)
    temp.x[i][i]=1;

    while(n)
    {
        if(n&1)
        temp=mutimatrix(temp,a);

        a=mutimatrix(a,a);
        n>>=1;
    }
    return temp;
} 

这个出题人直接把意思说的明明白白的,直接求那个矩阵的n次方就ok

#include <iostream> 
#include <cstring>
#include <cstdio>
using namespace std; 
#define LL long long 
const int mod=10000; 
struct matrix
{
    LL x[2][2];
};
matrix mutimatrix(matrix a,matrix b)
{
    matrix temp; 
    memset(temp.x,0,sizeof(temp.x));    
    for(int i=0;i<2;i++)
    for(int j=0;j<2;j++)
    for(int k=0;k<2;k++)
    {
        temp.x[i][j]+=a.x[i][k]*b.x[k][j];
        temp.x[i][j]%=mod;
    }
    return temp;
}

matrix k_powmatrix(matrix a,LL n)
{
    matrix temp;
    memset(temp.x,0,sizeof(temp.x));
    for(int i=0;i<2;i++)
    temp.x[i][i]=1;

    while(n)
    {
        if(n&1)
        temp=mutimatrix(temp,a);

        a=mutimatrix(a,a);
        n>>=1;
    }
    return temp;
} 


int main()
{
        int n;
        while(cin>>n ){
            if(n==0) {
                cout<<"0\n";
                continue;
            }
            if(n==1||n==2) {
                cout<<"1\n";
                continue;
            }
            if(n==-1) return 0;
            matrix st;
            memset(st.x,0,sizeof(st.x));
            st.x[0][0]=1;
            st.x[0][1]=1;
            st.x[1][0]=1;
            st.x[1][1]=0;

            st=k_powmatrix(st,n);


            printf("%lld\n",(st.x[0][1]+mod)%mod);
        }
} 

2.如何通过矩阵快速幂解决这种递推问题
先看普通斐波那契
参考:https://blog.csdn.net/wust_zzwh/article/details/52058209
f(n)=f(n-1)+f(n-2)
f(1)=f(2)=1
其实这个是个递推式,那么我们只要找到他的通项,就可以求出n为任何值时候的f(n)
那这个递推式我们看不出他是等比还是等差数列,通项也不会求,此时就需要用矩阵
因为矩阵有一个性质,一个常数矩阵乘以一个矩阵A(n),结果是矩阵B(n)
那如果A中各个元素对应于B中各个元素满足,A(n)=B(n-1),那这个整体就是个等比数列啊
这里写图片描述
我们设an=这里写图片描述
上面看作是q*a(n-1)=an,由等比数列通项公式得到
q^(n-1)*a1=an
现在q我们已经有了,就剩找a1了,a1我们都会求,带特殊值么,假设n=2,a2=q*a1,然后我们就求出a1了,所以之后求an就先求q^(n-1),再求q^(n-1) *a1
因为我是学过线性代数的,其实这有个大问题,矩阵的左乘右乘结果不一样,为了方便起见,我们通项乘的次序应该和第一个递推式的次序一样

还有个例子
f(1) = 1, f(2) = 1, f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7.

Given A, B, and n, you are to calculate the value of f(n).
这里写图片描述

图片来自:https://www.cnblogs.com/Blackops/p/5468284.html
通过这一题我们明白一个事情,那就是对我们那个矩阵数列的优化,2* 1矩阵可以写成2* 2矩阵,这样的话我们不用再弄一个函数去求2* 1矩阵*2*2矩阵了
还有一点,关于n那个次幂的事,这都是看a1对应的那个n是几,根小学学的等比数列一样一样的。。
还有个小窍门,我们不用一上来就推f(n),可以通过f(1),f(2)推f(3),推完之后把3变成n,1变成n-2,2变成n-1,然后带4验证。如果是,那就是,然后继续ok
参考代码:
https://blog.csdn.net/elbadaernu/article/details/77899130

#include <iostream> 
#include <cstring>
#include <cstdio>
using namespace std; 
#define LL long long 
const int mod=7; 
struct matrix
{
    LL x[2][2];
};
matrix mutimatrix(matrix a,matrix b)
{
    matrix temp; 
    memset(temp.x,0,sizeof(temp.x));    
    for(int i=0;i<2;i++)
    for(int j=0;j<2;j++)
    for(int k=0;k<2;k++)
    {
        temp.x[i][j]+=a.x[i][k]*b.x[k][j];
        temp.x[i][j]%=mod;
    }
    return temp;
}

matrix k_powmatrix(matrix a,LL n)
{
    matrix temp;
    memset(temp.x,0,sizeof(temp.x));
    for(int i=0;i<2;i++)
    temp.x[i][i]=1;

    while(n)
    {
        if(n&1)
        temp=mutimatrix(temp,a);

        a=mutimatrix(a,a);
        n>>=1;
    }
    return temp;
} 


int main()
{
        int a,b,n;
        while(scanf("%d%d%d",&a,&b,&n))
        {
            if(!(a+b+n)) break;
            if(n<=2)
            {
                printf("1\n");
                continue;
            }
            matrix st;
            memset(st.x,0,sizeof(st.x));
            st.x[0][0]=a;
            st.x[0][1]=1;
            st.x[1][0]=b;
            st.x[1][1]=0;
            matrix init;
            memset(init.x,0,sizeof(init.x));

            init.x[0][0]=1;
            init.x[0][1]=1;
            st=k_powmatrix(st,n-2);
            st=mutimatrix(init,st);

            printf("%lld\n",(st.x[0][0]+mod)%mod);
        }
        return 0; 

} 

猜你喜欢

转载自blog.csdn.net/qq_40828914/article/details/81807804