C++矩陣加速—————Warcraft III 守望者的煩惱

題目描述:

守望者-warden,長期在暗夜精靈的的首都艾薩琳內擔任視察監獄的任務,監獄是成長條行的,守望者warden擁有一個技能名叫“閃爍”,這個技能可以把她傳送到後面的監獄內查看,她比較懶,一般不查看完所有的監獄,只是從入口進入,然後再從出口出來就算完成任務了。

頭腦並不發達的warden最近在思考一個問題,她的閃爍技能是可以升級的,k級的閃爍技能最多可以向前移動k個監獄,一共有n個監獄要視察,她從入口進去,一路上有n個監獄,而且不會往回走,當然她並不用每個監獄都視察,但是她最後一定要到第n個監獄裏去,因爲監獄的出口在那裏,但是她並不一定要到第1個監獄。

守望者warden現在想知道,她在擁有k級閃爍技能時視察n個監獄一共有多少種方案?

輸入:

第一行是閃爍技能的等級k(1<=k<=10)
第二行是監獄的個數n(1<=n<=2^31-1)

輸出:

由於方案個數會很多,所以輸出它 mod 7777777後的結果就行了

輸入樣例:

2
4

輸出樣例:

5

提示:

樣例解釋:

 

把監獄編號1 2 3 4,閃爍技能爲2級,

一共有5種方案

→1→2→3→4

→2→3→4

→2→4

→1→3→4

→1→2→4

思路分析:

這一題的DP我們可以輕易看出,設f[i]爲到i節點的方案數,而狀態轉移方程就是:

f[i]=\sum ^{i-1}_{j=i-k}\;f[j]

但是衆所周知,2^{31}-1是一個較大的數,那麼我們的矩陣加速就上場了。

設b爲加速矩陣,假設k爲4則:

b=\begin{bmatrix} 1 & 1 & 0 &0 \\ 1 & 0&1 &0 \\ 1 & 0 & 0& 1\\ 1 & 0 & 0 &0 \end{bmatrix}

我們再設一個矩陣ans[1][k]

其中ans[1][1]表示f[i]的值,而ans[1][2]爲f[i-1],以此類推。

那我們的加速矩陣的作用就一目瞭然了。

第一列就是將f[i]的值求出,而之後的只不過是轉移了。

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
#define ll long long
ll n1,mod=7777777,k;
struct node{
    ll n,m,c[15][15];
    node()
    {
        memset(c,0,sizeof(c));
    }
    node operator*(const node &a)
    {
        node r;
        r.n=n;
        r.m=a.m;
        for(int i=1;i<=r.n;i++)
            for(int j=1;j<=r.m;j++)
                for(int k=1;k<=m;k++)
                    r.c[i][j]=(r.c[i][j]+(c[i][k]*a.c[k][j])%mod)%mod;
        return r;
    }
}b,ans;
void qkpow(node a,ll x)
{
    while(x)
    {
        if(x&1)
            ans=ans*a;
        a=a*a;
        x/=2;
    }
}
int main()
{
    scanf("%lld%lld",&k,&n1);
    b.n=k;
    b.m=k;
    for(int i=1;i<=k;i++)
        b.c[i][1]=1;
    for(int i=1;i<=k;i++)
        b.c[i][i+1]=1;
    ans.n=1;
    ans.m=k;
    ans.c[1][1]=1;
    qkpow(b,n1);
    printf("%lld",ans.c[1][1]);
}

 

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