HDU1588___矩阵快速幂and斐波拉契通项的矩阵算法

整个算法来自http://blog.sina.com.cn/s/blog_626631420100vsug.html

他本人写的非常的清楚,感谢。

题目中的公式:
f(0)=0 f(1)=1
f(n)=f(n-1)+f(n-2) (n>=2)
g(i)=k*i+b;
对于Fib序列:
如果用F表示上市中的矩阵就有 F(n+1) = AF(n) 是等比数列
g(i)=k*i+b 是等差数列
所以F(g(i)) = F(b) + F(b+k)+F(b+2k)+....+F(b+nk)
           = F(b) + (A^k)F(b) + (A^2k)F(b)+….+(A^nk)F(b)
提取公因式 F(b)
           = F(b) [ E +A^k + A^2k + ….+ A^nk]   (式中E表示的是单位矩阵)
令 K = A^k 后
                 E +A^k + A^2k + ….+ A^nk 变成 K^0+K^1+K^2+…+K^n
构造矩阵

              HDU <wbr>1588 <wbr>Gauss <wbr>Fibonacci

我的代码如下:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
#define LL long long

struct matrix
{
    LL data[2][2];
}E,A,O;

struct supMatrix
{
    matrix m[2][2];
}SUPE,SUPA;

int k,b,n,M;

void init()
{
    E.data[0][0] = E.data[1][1] = 1;
    E.data[0][1] = E.data[1][0] = 0;
    A.data[0][0] = A.data[0][1] = A.data[1][0] = 1;
    A.data[1][1] = 0;
    O.data[0][0] = O.data[0][1] = O.data[1][0] = O.data[1][1] = 0;
    SUPE.m[0][0] = SUPE.m[1][1] = E;
    SUPE.m[0][1] = SUPE.m[1][0] = O;
}

matrix m_mul(matrix X,matrix Y)
{
    matrix ans = O;
    for(int i=0;i<2;i++)
    {
        for(int j=0;j<2;j++)
        {
            for(int k=0;k<2;k++)
            {
                ans.data[i][j]+=X.data[i][k]*Y.data[k][j];
                ans.data[i][j]%=M;
            }
        }
    }
    return ans;
}

matrix m_power(int x,matrix st)
{
    matrix X = st;
    matrix Y = E;

    if(x==0)
        return Y;
    while(x!=1)
    {
        if(x&1)
        {
            x--;
            Y=m_mul(Y,X);
        }
        else
        {
            x=x>>1;
            X=m_mul(X,X);
        }
    }
    return m_mul(X,Y);
}

matrix m_add(matrix X,matrix Y)
{
    matrix ret = O;
    for(int i=0;i<2;i++)
    {
        for(int j=0;j<2;j++)
        {
            ret.data[i][j] = X.data[i][j]+Y.data[i][j];
            ret.data[i][j] %= M;
        }
    }
    return ret;
}

supMatrix sm_mul(supMatrix X,supMatrix Y)
{
    supMatrix ret;
    for(int i=0;i<2;i++)
    {
        for(int j=0;j<2;j++)
        {
            ret.m[i][j] = O;
            for(int k=0;k<2;k++)
            {
                ret.m[i][j] = m_add(ret.m[i][j],m_mul(X.m[i][k],Y.m[k][j]));
            }
        }
    }
    return ret;
}

supMatrix sm_power(int x,supMatrix st)
{
    supMatrix X = st;
    supMatrix Y = SUPE;
    if(x==0)
        return Y;
    while(x!=1)
    {
        if(x&1)
        {
            x--;
            Y=sm_mul(Y,X);
        }
        else
        {
            x=x>>1;
            X=sm_mul(X,X);
        }
    }
    return sm_mul(X,Y);
}

int main()
{
    init();

    while(~scanf("%d%d%d%d",&k,&b,&n,&M))
    {
        matrix Fb = m_power(b,A);
        matrix K = m_power(k,A);
        SUPA.m[0][0] = K;
        SUPA.m[0][1] = SUPA.m[1][1] = E;
        SUPA.m[1][0] = O;

        supMatrix ans1 = sm_power(n,SUPA);
        matrix KN = ans1.m[0][1];
        matrix ans2 = m_mul(Fb,KN);
        printf("%I64d\n",ans2.data[1][0]);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值