矩阵加速(递推式)(数列)

P1939 【模板】矩阵加速(数列)
题目描述
a[1]=a[2]=a[3]=1

a[x]=a[x-3]+a[x-1] (x>3)

求a数列的第n项对1000000007(10^9+7)取余的值。

输入输出格式
输入格式:
第一行一个整数T,表示询问个数。

以下T行,每行一个正整数n。

输出格式:
每行输出一个非负整数表示答案。

输入输出样例

输入样例#1:
3
6
8
10
输出样例#1:
4
9
19


此题乍一看可以用离散数学里学过的递推公式求解, 但是x**3 - x**2 - 1 = 0个特征方程似乎是有虚数解, 那么看来是不行的.

再回顾之前学过的矩阵快速幂求斐波那契数列,这个数列和斐波那契非常相似,都是递推,那么是否可以用同样的方法用矩阵去做呢?

结合题的名字”【模板】矩阵加速(数列)”, 标程应该就是这样了吧.

OK, 经过推导构造出了矩阵[[1, 0, 1], [1, 0, 0], [0, 1, 0]].

思路和斐波那契数列的矩阵快速幂是一样的.

找出关系矩阵 -> 矩阵计算 + 快速幂

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

const LL mode = 1000000007;

void calc(LL ans[3][3], LL matrix[3][3])
{
    LL tmp[3][3];
    memset(tmp, 0, sizeof(tmp));
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            for (int k = 0; k < 3; ++k) {
                tmp[i][j] += ans[i][k] * matrix[k][j];
                tmp[i][j] %= mode;
            }
        }
    }
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            ans[i][j] = tmp[i][j];
        }
    }
}

int main()
{
    LL T, n;
    cin >> T;
    for (int i = 0; i < T; ++i) {
        LL matrix[3][3] = {{1, 0, 1}, {1, 0, 0}, {0, 1, 0}};
        LL ans[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
        cin >> n;
        if (n <= 3) {
            cout << 1 << endl;
            continue;
        }
        n -= 3;
        while (n) {
            if (n & 1) {
                calc(ans, matrix);
            }
            calc(matrix, matrix);
            n /= 2;
        }
        cout << (ans[0][0] + ans[0][1] + ans[0][2]) % mode << endl;
    }
}

猜你喜欢

转载自blog.csdn.net/wjh2622075127/article/details/81221949
今日推荐