題目描述:
守望者-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節點的方案數,而狀態轉移方程就是:
但是衆所周知,是一個較大的數,那麼我們的矩陣加速就上場了。
設b爲加速矩陣,假設k爲4則:
我們再設一個矩陣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]);
}