矩阵十题【七】vijos 1067 Warcraft III 守望者的烦恼

题目链接:https://vijos.org/p/1067

题目大意:给你一个k以及n,k代表最多走的步数,n代表一共要走的步数。

问一共有多少种方法,结果mod7777777

题目意思是很明了,具体的公式也能推出来

状态转移方程为:f[n]=f[n-1]+f[n-2]+....f[n-k]

f[0]=1

当k=1,   f[1]=1;

            f[2]=f[1]=1;

            f[3]=f[2]=1;

            f[4]=f[3]=1;

当k=2,   f[1]=1;

             f[2]=f[1]+f[0]=2;

             f[3]=f[2]+f[1]=3;

             f[4]=f[3]+f[2]=5;

当k=3,    f[1]=1;

             f[2]=f[1]+f[0]=2;

             f[3]=f[2]+f[1]+f[0]=4;

             f[4]=f[3]+f[2]+f[1]=7;

k的数据量只有10,所以我们构造出一个10*10的矩阵,本题主要考察的是矩阵快速幂以及构造这个矩阵。


若k等于4

 【 [ 0  1  0  0]          [f(k-4)]       [f(k-3)]

     [ 0  0  1  0]     *    [f(k-3)]   =  [f(k-2)]

     [ 0  0  0  1]          [f(k-2)]       [f(k-1)]

     [ 1  1  1  1] 】      [f(k-1)]       [f( k )] 

根据上面的例子我们可以很容易构造出这个矩阵出来。

#include<iostream>
#include<stdio.h>
#include<cstring>
#define LL long long
using namespace std;
const LL MAX = 15;


struct Matrix
{
    LL v[MAX][MAX];
};

LL n, M=7777777;

Matrix mtAdd(Matrix A, Matrix B)        // 求矩阵 A + B
{
    LL i, j;
    Matrix C;
    for(i = 0; i < n; i ++)
        for(j = 0; j < n; j ++)
            C.v[i][j]=(A.v[i][j]+B.v[i][j])% M;
    return C;
}

Matrix mtMul(Matrix A, Matrix B)        // 求矩阵 A * B
{
    LL i, j, k;
    Matrix C;
    for(i = 0; i < n; i ++)
        for(j = 0; j < n; j ++)
        {
            C.v[i][j] = 0;
            for(k = 0; k < n; k ++)
                C.v[i][j] = ((A.v[i][k] * B.v[k][j])%M + C.v[i][j]) % M;
        }
    return C;
}

Matrix mtPow(Matrix A, LL k)           // ?ó???ó A ^ k
{
    if(k == 0)
    {
        memset(A.v, 0, sizeof(A.v));
        for(LL i = 0; i < n; i ++)
            A.v[i][i] = 1;
        return A;
    }

    if(k == 1) return A;

    Matrix C = mtPow(A, k / 2);
    if(k % 2 == 0)
        return mtMul(C, C);
    else
        return mtMul(mtMul(C, C), A);
}


void out(Matrix A)
{
    for(LL i=0;i<n;i++)
    {
        for(LL j=0;j<n;j++)
        cout<<A.v[i][j]<<" ";
        cout<<endl;
    }
    cout<<endl;
}


Matrix mtCal(Matrix A, LL k)    // 求S (k) = A + A2 + A3 + … + Ak
{
    if(k == 1) return A;
    Matrix B = mtPow(A, (k+1) / 2);
    Matrix C = mtCal(A, k / 2);
    if(k % 2 == 0)
        return mtMul(mtAdd(mtPow(A, 0), B), C);   // 如S(6) = (1 + A^3) * S(3)。
    else
        return mtAdd(A, mtMul(mtAdd(A, B), C));   // 如S(7) = A + (A + A^4) * S(3)
}

int main ()
{

      int k;
      while(~scanf("%d%d",&n,&k))
{

      Matrix A;
      memset(A.v,0,sizeof(A));
      for(LL i=0;i<n-1;i++) A.v[i+1][i]=1;
      for(LL i=0;i<n;i++)   A.v[i][n-1]=1;
      //out(A);

      A=mtPow(A,k-1);
      //out(A);

      Matrix ans;
      memset(ans.v,0,sizeof(ans.v));
      ans.v[0][0]=1;
      for(LL i=1;i<=n;i++)
      {
          ans.v[0][i]=1;
      for(LL j=0;j<i;j++)
           ans.v[0][i]+=ans.v[0][j];
      }
      //out(ans);

      A=mtMul(ans,A);

      //out(A);

      cout<<A.v[0][0]<<endl;
}
}







  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值