背景
守望者-warden,长期在暗夜精灵的的首都艾萨琳内担任视察监狱的任务,监狱是成长条行的,守望者warden拥有一个技能名叫“闪烁”,这个技能可以把她传送到后面的监狱内查看,她比较懒,一般不查看完所有的监狱,只是从入口进入,然后再从出口出来就算完成任务了。
描述
头脑并不发达的warden最近在思考一个问题,她的闪烁技能是可以升级的,k级的闪烁技能最多可以向前移动k个监狱,一共有n个监狱要视察,她从入口进去,一路上有n个监狱,而且不会往回走,当然她并不用每个监狱都视察,但是她最后一定要到第n个监狱里去,因为监狱的出口在那里,但是她并不一定要到第1个监狱。
守望者warden现在想知道,她在拥有k级闪烁技能时视察n个监狱一共有多少种方案?
输入格式
第一行是闪烁技能的等级k(1<=k<=10)
第二行是监狱的个数n(1<=n<=2^31-1)
输出格式
由于方案个数会很多,所以输出它 mod 7777777后的结果就行了
样例1
样例输入1
2
4
Copy
样例输出1
5
Copy
限制
各个测试点1s
提示
把监狱编号1 2 3 4,闪烁技能为2级,
一共有5种方案
→1→2→3→4
→2→3→4
→2→4
→1→3→4
→1→2→4
小提示:建议用int64,否则可能会溢出
解析:
令表示到第个监狱的方案数,则有:
如果直接进行递推肯定是不行的,所以我们考虑构造矩阵。
构造两个矩阵:
容易得出:
于是矩阵快速幂即可。注意初始化
代码:
#include <bits/stdc++.h>
using namespace std;
const int mod=7777777;
const int Max=12;
int n,m,k;
int ans[Max],a[Max][Max];
inline int get_int()
{
int x=0,f=1;
char c;
for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
if(c=='-') f=-1,c=getchar();
for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
return x*f;
}
inline void mul(int ans[Max],int a[Max][Max])
{
int c[Max];
memset(c,0,sizeof(c));
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
c[j]=(c[j]+1ll*ans[k]*a[k][j]%mod)%mod;
memcpy(ans,c,sizeof(c));
}
inline void mulself(int a[Max][Max])
{
int c[Max][Max];
memset(c,0,sizeof(c));
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
c[i][j]=(c[i][j]+1ll*a[i][k]*a[k][j]%mod)%mod;
memcpy(a,c,sizeof(c));
}
inline void solve(int n) //矩阵快速幂
{
while(n)
{
if(n&1) mul(ans,a);
n>>=1;
mulself(a);
}
}
int main()
{
n=get_int(),m=get_int();
ans[1]=1; //相当于初始化f[0]=0
for(int i=1;i<=n;i++) a[i][1]=1; //构造矩阵
for(int i=1;i<=n;i++) a[i][i+1]=1; //构造矩阵
solve(m);
cout<<ans[1]<<"\n";
return 0;
}