矩阵加速递推,身为不会构造矩阵的蒟蒻,我没有构造出来,所以滚粗了QAQ
我们不难发现我们可用的步数只有1->k,那么我们就发现了一个有趣的性质,当前项i(i>=k)只与f[i-1]~f[i-k]有关,那么可以轻松的写出一个递推公式f[i]=Σ(j∈1->k)f[i-j],也就是说新矩阵和原矩阵的不同就在于将原矩阵平移一个单位,并将下一项填进去,下一项又满足f[i]等于前几项之和,那么 我们可以得知矩阵的首项是转移前矩阵每一个f[i]的和,我们令矩阵的第一行表示转移到i的方案数,那么新矩阵的第一行第一个数是旧矩阵第一行的和,那么转移矩阵的第一列就要全是1,然后还要实现平移,发现新矩阵的第i位是原矩阵的第i-1位,那么我们可以得出每行的a[i][i+1]=1便可以将上一个数平移过来,然后矩阵快速幂转移就好,因为新数出现在第一行第一列,所以输出a[1][1]即为结果
代码
//By AcerMo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int mod=7777777;
struct mtix
{
int x[15][15];
mtix(){memset(x,0,sizeof(x));}
}f;
int n,m;
mtix mul(mtix a,mtix b)
{
mtix c;
for (int i=1;i<=m;i++)
for (int j=1;j<=m;j++)
for (int k=1;k<=m;k++)
c.x[i][j]=(long long int )((long long int)c.x[i][j]+(long long int )a.x[i][k]*b.x[k][j])%mod;
return c;
}
void mpow(int y)
{
mtix ans;
for (int i=1;i<=m;i++) ans.x[i][i]=1;
for (;y;f=mul(f,f),y>>=1)
if (y&1) ans=mul(ans,f);
cout<<ans.x[1][1];
return ;
}
signed main()
{
cin>>m>>n;
if (m<=0) return puts("0"),0;
if (n==1) return puts("1"),0;
for (int i=1;i<=m;i++) f.x[i][1]=1;
for (int i=1;i<m;i++) f.x[i][i+1]=1;
mpow(n);
}
//一起熬梦,即使朝不保夕