hdu 1588 - Gauss Fibonacci


对于Fib数列:矩阵A={ {1, 1}, {1, 0} }, f[i]=A^i的[0, 1]项,即右上角的那一项。

所以sum{ f(g(i)) } = sum { f(k*i+b) } =   f(b) + f(k+b) + f(2*k+b)+......

令F(i) = A^i;

F(b) + F(k+b) + F(2*k+b)+...... = A^b + A^(k+b) + A^(2*k+b)...... = A^b * ( A^0 + A^k + A^(2*k)......)


令K = A^k;

可以用大矩阵的快速幂求出A^0 + A^k + A^(2*k)......




还有一种二分求解A^k + A^(2*k) + ...... + A^n


令G(n)=A^k + A^(2*k) + ...... + A^n

n是偶数时:G(n) = G(n/2) * (A^(n/2) + E)

n是奇数时:G(n) = A^n + G(n-1)

二分边界是:n==1时,return A;



下面是AC的代码:



#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef unsigned long long LLU;
const int N=10;
int MOD=1e9;

struct Matrix
{
    LL m[N][N];
} e, u;

void init()
{
    e.m[0][0]=e.m[1][1]=u.m[0][0]=u.m[0][1]=u.m[1][0]=1;
    e.m[0][1]=e.m[1][0]=u.m[1][1]=0;
}
int n, k, b;

Matrix Mult(Matrix a, Matrix b)
{
    Matrix ans;
    for(int i=0; i<2; i++)
        for(int j=0; j<2; j++)
        {
            ans.m[i][j]=0;
            for(int k=0; k<2; k++)
                ans.m[i][j]=(ans.m[i][j]+a.m[i][k]*b.m[k][j])%MOD;
        }
    return ans;
}

Matrix Pow(Matrix a, int b)
{
    Matrix ans;
    for(int i=0; i<2; i++)
        for(int j=0; j<2; j++)
            ans.m[i][j]=(i==j);
    while(b)
    {
        if(b&1)ans=Mult(ans, a);
        a=Mult(a, a);
        b>>=1;
    }
    return ans;
}

Matrix Add(Matrix a, Matrix b)
{
    for(int i=0; i<2; i++)
        for(int j=0; j<2; j++)
            a.m[i][j]=(a.m[i][j]+b.m[i][j])%MOD;
    return a;
}

Matrix BinarySum(Matrix a, int n)
{
    if(n==1)return a;
    return (n&1) ? Add(Pow(a, n), BinarySum(a, n-1)) : Mult(BinarySum(a, n>>1), Add(Pow(a, n>>1), e));
}

int main()
{
    init();
    while(~scanf("%d%d%d%d", &k, &b, &n, &MOD))
    {
        Matrix A=Pow(u, b);
        Matrix K=Pow(u, k);

        Matrix ans=Mult(A, Add(e, BinarySum(K, n-1)));
        printf("%d\n", ans.m[0][1]);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值