POJ 3070 Fibonacci.(矩阵快速幂)

6 篇文章 0 订阅
3 篇文章 0 订阅

解题思路:用公式递推显然是会超时的,于是根据题目明显的提示,就想到用矩阵快速幂。

之所以快,是运用了二分的思想,算出了矩阵A的值,那么我可以一步算出A*A的值,进而一步算出A*A*A*A的值,进而……

题目链接:点击打开链接

方法一:

#include<cstdio>
#include<algorithm>
#define N 100000
#define MOD 10000
using namespace std;

int f[N];
int Get(int n) //将n转化成二进制并存到数组f
{
    int cnt=0;
    while(n)
    {
        if(n%2) f[cnt++]=1;
        else f[cnt++]=0;
        n/=2;
    }
    return cnt;
}
int b[2][2],s[2][2]; //数组b保存矩阵A,A*A,A*A*A*A……数组s保存答案。
void Cal(int k)
{
    int t[2][2];
    for(int i=0;i<2;i++)
        for(int j=0;j<2;j++)
            t[i][j]=s[i][j];
    if(k) //此二进制位为1.
    {
        s[0][0]=((t[0][0]*b[0][0])%MOD+(t[0][1]*b[1][0])%MOD)%MOD; //矩阵乘法
        s[0][1]=((t[0][0]*b[0][1])%MOD+(t[0][1]*b[1][1])%MOD)%MOD;
        s[1][0]=((t[1][0]*b[0][0])%MOD+(t[1][1]*b[1][0])%MOD)%MOD;
        s[1][1]=((t[1][0]*b[0][1])%MOD+(t[1][1]*b[1][1])%MOD)%MOD;
    }
    for(int i=0;i<2;i++)
        for(int j=0;j<2;j++)
            t[i][j]=b[i][j];
    //继续求下一个A*A*A*A*A*A*A*A……
    b[0][0]=((t[0][0]*t[0][0])%MOD+(t[0][1]*t[1][0])%MOD)%MOD; 
    b[0][1]=((t[0][0]*t[0][1])%MOD+(t[0][1]*t[1][1])%MOD)%MOD;
    b[1][0]=((t[1][0]*t[0][0])%MOD+(t[1][1]*t[1][0])%MOD)%MOD;
    b[1][1]=((t[1][0]*t[0][1])%MOD+(t[1][1]*t[1][1])%MOD)%MOD;
}
int main()
{
    int n;
    while(scanf("%d",&n)==1)
    {
        if(n==-1)
            break;
        int len=Get(n);
        b[0][0]=1; b[0][1]=1; b[1][0]=1; b[1][1]=0;  //初始化。
        s[0][0]=1; s[0][1]=0; s[1][0]=0; s[1][1]=1;
        for(int i=0;i<len;i++)
            Cal(f[i]);
        printf("%d\n",s[0][1]);
    }
    return 0;
}


方法二:

更棒的解法来了,既然是二分,那么我们用递归的方法来写;

eg: S(6)=A^6; -> S(6)=S(3)*S(3);->S(3)=A*S(1)*S(1);S(1)=A; return;

#include<cstdio>
#include<cstring>
#include<algorithm>
#define MOD 10000
using namespace std;

struct Matrix
{
    int f[5][5];
};
int m=2; //矩阵为2*2
Matrix Mul(Matrix U,Matrix V) //矩阵相乘
{
    Matrix S;
    memset(S.f,0,sizeof(S.f));
    for(int k=0;k<m;k++)
        for(int i=0;i<m;i++)
            for(int j=0;j<m;j++)
                S.f[k][i]=(U.f[k][j]*V.f[j][i]+S.f[k][i])%MOD;
    return S;
}
Matrix Pow(Matrix S,int k) //求解 A^k
{
    if(k==0)
    {
        memset(S.f,0,sizeof(S.f));
        for(int i=0;i<m;i++)
            S.f[i][i]=1;
        return S;
    }
    if(k==1)
        return S;
    Matrix X=Pow(S,k/2);
    if(k%2)
        return Mul(Mul(X,X),S);
    else
        return Mul(X,X);
}
int main()
{
    int n;
    while(scanf("%d",&n)==1)
    {
        if(n==-1)
            break;
        Matrix A;
        A.f[0][0]=1; A.f[0][1]=1;
        A.f[1][0]=1; A.f[1][1]=0;
        Matrix S=Pow(A,n);
        printf("%d\n",S.f[0][1]);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值