【打表找规律+矩阵快速幂】number number number HDU - 6198

本文介绍了一种利用矩阵快速幂方法解决mjf-bad数问题的算法。该问题要求找到最小的不能由不超过k个斐波那契数(可重复选取)累加得到的数,并对结果取模。文章首先通过打表发现了规律,然后采用矩阵快速幂高效计算斐波那契数列的大数值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Think:
1知识点:打表找规律+矩阵快速幂
2题意:给定一个数n,若可以从斐波那契数列中寻找不超过k个数(可重发选择)使得这k个数的累加和为n,则称n为mjf−good,若找不到不超过k个数(可重复选择)使得这k个数的累加和为n,则称n为mjf−bad,输入k(1≤k≤109),输出最小的mjf_bad modulo 998244353。
3方法:
1>打表找规律,发现F[k] = f[2*(k+1)+1] - 1
2>k太大,通过矩阵快速幂求解斐波那契数列第n项
这里写图片描述
矩阵快速幂求解斐波那契数列——建议参考博客
4反思:
1>矩阵乘法注意不要爆int
2>矩阵乘法注意及时取模

vjudge题目链接

以下为Wrong Answer代码——矩阵乘法时爆int导致运算错误

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

using namespace std;

const int mod = 998244353;

struct Matrix{
    int v[4][4];
};

Matrix multiply(Matrix x, Matrix y, int Matrix_len);
Matrix matrix_pow(Matrix a, int k, int Matrix_len);

int main(){
    int k, kk, ans;
    Matrix x, y, z;
    while(~scanf("%d", &k)){
        x.v[0][0] = 1, x.v[0][1] = 1, x.v[1][0] = 1, x.v[1][1] = 0;
        y.v[0][0] = 1, y.v[0][1] = 0, y.v[1][0] = 0, y.v[1][1] = 0;

        kk = 2*(k+1)+1;
        x = matrix_pow(x, kk-1, 2);
        z = multiply(x, y, 2);

        ans = (z.v[0][0]-1+mod) % mod;
        printf("%d\n", ans);
    }
    return 0;
}
Matrix multiply(Matrix x, Matrix y, int Matrix_len){
    Matrix z;
    memset(z.v, 0, sizeof(z.v));
    for(int i = 0; i < Matrix_len; i++){
        for(int j = 0; j < Matrix_len; j++){
            for(int k = 0; k < Matrix_len; k++){
                z.v[i][j] += x.v[i][k] * y.v[k][j];
                z.v[i][j] %= mod;
            }
        }
    }
    return z;
}
Matrix matrix_pow(Matrix a, int k, int Matrix_len){
    Matrix b;
    for(int i = 0; i < Matrix_len; i++){
        for(int j = 0; j < Matrix_len; j++){
            i == j? b.v[i][j] = 1: b.v[i][j] = 0;
        }
    }
    while(k){
        if(k & 1)
            b = multiply(b, a, 2);
        a = multiply(a, a, 2);
        k >>= 1;
    }
    return b;
}

以下为Accepted代码

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

using namespace std;

typedef long long LL;

const int mod = 998244353;

struct Matrix{
    LL v[4][4];
};

Matrix multiply(Matrix x, Matrix y, int Matrix_len);/*矩阵乘法*/
Matrix matrix_pow(Matrix a, int k, int Matrix_len);/*矩阵快速幂*/

int main(){
    LL k, kk, ans;
    Matrix x, y, z;
    while(~scanf("%lld", &k)){
        x.v[0][0] = 1, x.v[0][1] = 1, x.v[1][0] = 1, x.v[1][1] = 0;
        y.v[0][0] = 1, y.v[0][1] = 0, y.v[1][0] = 0, y.v[1][1] = 0;

        kk = 2*(k+1)+1;
        x = matrix_pow(x, kk-1, 2);
        z = multiply(x, y, 2);

        ans = (z.v[0][0]-1+mod) % mod;
        printf("%lld\n", ans);
    }
    return 0;
}
Matrix multiply(Matrix x, Matrix y, int Matrix_len){
    Matrix z;
    memset(z.v, 0, sizeof(z.v));
    for(int i = 0; i < Matrix_len; i++){
        for(int j = 0; j < Matrix_len; j++){
            for(int k = 0; k < Matrix_len; k++){
                z.v[i][j] += x.v[i][k] * y.v[k][j];
                z.v[i][j] %= mod;
            }
        }
    }
    return z;
}
Matrix matrix_pow(Matrix a, int k, int Matrix_len){
    Matrix b;
    for(int i = 0; i < Matrix_len; i++){
        for(int j = 0; j < Matrix_len; j++){
            i == j? b.v[i][j] = 1: b.v[i][j] = 0;
        }
    }
    while(k){
        if(k & 1)
            b = multiply(b, a, 2);
        a = multiply(a, a, 2);
        k >>= 1;
    }
    return b;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值