YTU 3374: H胖胖的健身計劃

3374: H胖胖的健身計劃

鏈接: 我在這裏快點我.

題目描述

L老師佈置了一道思考題,一個人一次可以上一個臺階,也可以上兩個臺階,問上到n級臺階有多少種走法?H胖胖非常聰明,拿出胖胖的小手掐指算起來。登上第一級臺階有一種登法;登上兩級臺階,有兩種登法;登上三級臺階,有三種登法;登上四級臺階,有五種方法……所以,1,2,3,5,8,13,……。
H胖胖爲了保持身體苗條,給自己制定了一個鍛鍊計劃,決定用剛纔計算的數列確定每天自己鍛鍊的步數,就是說第1天走1步,第2天走2步,第3天走5步,第4天走8步,第5天走13步,……。
H胖胖的同學LYQ正好在學習矩陣相乘,幫他想到了一個快遞計算的方法如下公式所示。
在這裏插入圖片描述
H胖胖拿出手機查閱了快速冪的百度百科,看到如下信息:
快速冪
顧名思義,快速冪就是快速算底數的n次冪。其時間複雜度爲 O(log₂N), 與樸素的O(N)相比效率有了極大的提高。
原理
以下以求a的b次方來介紹:
把b轉換成二進制數。
該二進制數第i位的權爲
例如
11的二進制是1011
11 = 2³×1 + 2²×0 + 2¹×1 + 2º×1
因此,我們將a¹¹轉化爲算
在這裏插入圖片描述
但是H胖胖的手機太不給力,後面的代碼實在看不清了,請正在做題的你幫幫他吧。

輸入
一個整數n(0<n<10^12)
輸出
H胖胖走的步數%100007的結果

樣例輸入

6

樣例輸出

13

思路:
題目數據範圍太大,暴力會T。所以我們考慮用矩陣快速冪來做,初始化一個單位矩陣,再重載一下乘法,最後求出來左邊矩陣的n-2次方,再和右邊矩陣相乘得出一個兩行一列的矩陣,第一個元素就是我們要的答案,再模10007就解決了。

AC代碼:

#include <bits/stdc++.h>
#define mod(x)  ((x)%MOD)
 
using namespace std;
typedef long long ll;
const ll maxn = 2;
const ll MOD  = 100007;
 
ll n;
struct mat
{
    ll m[maxn][maxn];
}unit;
 
mat operator * (mat a, mat b)   // 重載乘法
{
    mat ret;
    ll x;
    // 矩陣相乘
    for(ll i=0;i<maxn;i++){
        for(ll j=0;j<maxn;j++){
            x = 0;
            for(ll k= 0;k<maxn;k++){
                x += mod((ll)a.m[i][k]*b.m[k][j]);
            }
            ret.m[i][j] = mod(x); //宏定義模100007
        }
    }
    return ret;
}
 
void init_unit()    //初始化一個單位矩陣
{
    for(ll i = 0; i < 10; i++)
        unit.m[i][i] = 1;
    return ;
}
 
mat kpow_mat(mat a, ll b)
{
    mat ret = unit; //單位矩陣
    while(b){
        if(b&1) ret = ret * a;  // 這裏我們在重載乘法的時候就已經模100007了
        a = a * a;
        b>>=1;
    }
    return ret ;
}

int main()
{
    init_unit();
    scanf("%lld", &n);
    mat a,b;
    if(n == 1 || n == 2 || n == 3){
        printf("%lld", n);
    }else {
        b.m[0][0] = 1, b.m[1][0] = 1;
        b.m[0][1] = 1, b.m[1][1] = 0;
        
        a.m[0][0] = 2, a.m[0][1] = 1;
        b = kpow_mat(b, n-2);
        a = a*b;
        printf("%lld", a.m[0][0]%MOD);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章