HLG 1126 Final Destination II

是遞推啊......是遞推啊......

沒錯真的是非常簡單的遞推,你沒有判斷錯誤!

你每次可以上1個臺階,上2個臺階,上3個臺階,給出n級臺階。問你有幾種走法?

我強迫症範的時候,會一次上一個臺階,走錯了,會重新走一遍敲打

那麼遞推公式非常簡單的出來了:

an=an-1+an-2+an-3

當n=1的時候爲1,當n=2的時候爲2,當n=3的時候爲4;

即a[1]=1,a[2]=2,a[3]=4;

當n的時候,將規模縮小到n-1,即最後一步走一個臺階,那麼有a[n-1]種方法;

若最後一次走兩個臺階,那麼有a[n-2]種方法,最後一次走三個臺階,那麼有a[n-3]種方法。

遞推公式就這麼出來了微笑

一般情況,我們都會使用數組存儲,一次性算完,然後直接輸出。顯然,n的規模10^9

顯然數組是做不到的。若是循環算的話,那時間想想也是醉了。

因此這裏引入了一個新的方法,優化遞推公式(應該只適用於一階方程):

矩陣乘方

http://blog.csdn.net/masked__dance/article/details/40351293

具體的矩陣乘方分析請看鏈接:

/**本題爲遞推公式的優化**/
#include <iostream>
using namespace std;
#include <stdio.h>
#include <string.h>
#define mod 1000000007
///遞推公式爲an=an-1+an-2+an-3
void mul(long long a[][3],long long b[][3])
{
    long long c[3][3];
    for(int i=0;i<3;i++)
        for(int j=0;j<3;j++){
            c[i][j]=0;
            for(int k=0;k<3;k++)
                c[i][j]+=((a[i][k]%mod)*(b[k][j]%mod))%mod;
        }
    for(int i=0;i<3;i++)
        for(int j=0;j<3;j++)
            b[i][j]=c[i][j]%mod;
}
long long quickPow(long long n,long long a[][3],long long b[][3])
{
    while(n)
    {
        if(n&1)
            mul(a,b);
        n=n>>1;
        mul(a,a);
    }
    return b[0][0];
}
int main()
{
    long long T,k,n;
    scanf("%lld",&T);
    for(k=1;k<=T;k++)
    {
        scanf("%lld",&n);
        long long stairs[3][3]={4,0,0,2,0,0,1,0,0};///初始化更新還有什麼清空的都要注意
        long long co[3][3]={1,1,1,1,0,0,0,1,0};
        printf("Case %lld:\n",k);
        switch(n){
        case 0:printf("1\n");break;
        case 1:printf("1\n");break;
        case 2:printf("2\n");break;
        case 3:printf("4\n");break;
        default:printf("%lld\n",quickPow(n-3,co,stairs));break;///注意這裏的n-3
        }
       /* if(n==0)
            printf("1\n");
        else if(n == 1)
            printf("1\n");
        else if(n == 2)
            printf("2\n");
        else
            printf("%lld\n",quickPow(n-3,co,stairs));*/

    }
    return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章