HDOJ 1005 Number Sequence 矩阵快速幂 代码 + 解析

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1005

部分题头:

Problem Description

A number sequence is defined as follows:

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).

Input

The input consists of multiple test cases. Each test case contains 3 integers A, B and n on a single line (1 <= A, B <= 1000, 1 <= n <= 100,000,000). Three zeros signal the end of input and this test case is not to be processed.

Output

For each test case, print the value of f(n) on a single line.

大意就是给你个递推表达式 f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7,其中 f(1) = 1, f(2) = 1,要你求f(n)。

首先这个n的范围很大,上限是1e8,就别说什么递归了,就是O(n)的一个while递推都会超时。网上不少题解说找规律,这里我觉得用矩阵快速幂来做应该才是正解。思路就是模仿斐波那契数列的矩阵快速幂做法,构造一个包含A,B的矩阵,然后用矩阵快速幂求解,构建出来的矩阵快速幂表达式大概是这样的:

还要注意的是,递推式中还有求余,根据数论里面的知识有:(a * b) % m = (a%m * b%m) % m,修改一下矩阵乘法的代码,在每次两数相乘时先求余,最后得到结果矩阵之后再求一次余即可。

AC代码:

#include <string>
#include <cstring>
#include <algorithm>
#include <cstdio>

using namespace std;

#define M 2

int m = 0;

struct Mat
{

    int data[M][M];
    Mat()
    {
        memset(data, 0, sizeof(data));
    }

    void print()
    {
        for (int i = 0; i < M; ++i)
        {
            for (int j = 0; j < M; ++j)
                printf("%d ", data[i][j]);
            printf("\n");
        }
        printf("\n");
    }
};

Mat multipy(const Mat &ma, const Mat &mb, const int m)
{
    Mat res;
    for (int i = 0; i < M; ++i)
        for (int j = 0; j < M; ++j)
            for (int k = 0; k < M; ++k)
                res.data[i][j] += ma.data[i][k] % m * mb.data[k][j] % m;
    return res;
}

Mat mqp(Mat mat, int n, int m)
{

    Mat res;
    res.data[0][0] = res.data[1][1] = 1;
    while (n)
    {
        if (n & 1)
            res = multipy(res, mat, m);
        mat = multipy(mat, mat, m);
        //mat.print();
        n >>= 1;
    }
    return res;
}

int calc(int n, int a, int b, int m)
{
    if (n == 1 || n == 2)
        return 1;
    --n;

    Mat A;
    A.data[0][0] = 0;
    A.data[0][1] = 1;
    A.data[1][0] = b;
    A.data[1][1] = a;
    //A.print();
    Mat F;
    F.data[0][0] = 1;
    F.data[0][1] = 0;
    F.data[1][0] = 1;
    F.data[1][1] = 0;

    Mat tmp = multipy(mqp(A, n, m), F, m);
    return tmp.data[0][0] % m;
}

int main()
{
    //freopen("1.txt", "r", stdin);
    int a, b, n;
    while (1)
    {
        scanf("%d%d%d", &a, &b, &n);
        if (a == 0 && b == 0 && n == 0)
            break;
        printf("%d\n", calc(n, a, b, 7));
    }

    return 0;
}

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值