[NOIP模拟赛]Fy ' s Dota2

矩阵加速递推,身为不会构造矩阵的蒟蒻,我没有构造出来,所以滚粗了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);
}
//一起熬梦,即使朝不保夕

猜你喜欢

转载自blog.csdn.net/acerandaker/article/details/81135219
今日推荐