HihoCoder 1504 : 骑士游历 (矩阵乘法)

描述

在8x8的国际象棋棋盘上给定一只骑士(俗称“马”)棋子的位置(R, C),小Hi想知道从(R, C)开始移动N步一共有多少种不同的走法。  

输入

第一行包含三个整数,N,R和C。

对于40%的数据, 1 <= N <= 1000000

对于100%的数据, 1 <= N <= 1000000000 1 <= R, C <= 8

输出

从(R, C)开始走N步有多少种不同的走法。由于答案可能非常大,你只需要输出答案模1000000007的余数。

样例输入

2 1 1

样例输出

12

此类题在Floyd算法里用到过,即问从a出发,走x步,有多少种方法到b点。 充分利用floyd和矩阵的相似性(3个for语句),就可以求出。

很久没有写矩阵了,温故一下。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=70;
#define ll long long
const int Mod=1e9+7;
int x[8]={2,2,-2,-2,1,1,-1,-1};
int y[8]={1,-1,1,-1,2,-2,2,-2};
struct mat
{
    ll M[maxn][maxn];
    mat() { memset(M,0,sizeof(M)); }
    mat friend operator *(mat a,mat b)
    {
        mat res;
        for(int k=1;k<=64;k++)
         for(int i=1;i<=64;i++)
          for(int j=1;j<=64;j++){
                res.M[i][j]=(res.M[i][j]+a.M[i][k]*b.M[k][j])%Mod;
         } return res;
    }
    mat friend operator ^(mat a,int x)
    {
       mat res; for(int i=1;i<=64;i++) res.M[i][i]=1;
       while(x){
            if(x&1) res=a*res; a=a*a; x/=2;
       } return res;
    }
};    

mat base;
void prepare()
{
    for(int i=1;i<=8;i++)
     for(int j=1;j<=8;j++)
      for(int k=0;k<8;k++)
        if(i+x[k]>=1&&i+x[k]<=8&&j+y[k]>=1&&j+y[k]<=8)
          base.M[(i-1)*8+j][(i+x[k]-1)*8+j+y[k]]=1;
}
int main()
{
    int N,R,C,ans=0;
    scanf("%d%d%d",&N,&R,&C);
    prepare();
    base=base^N;
    for(int i=1;i<=64;i++)  ans=(ans+base.M[(R-1)*8+C][i])%Mod;
    printf("%d
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/hua-dong/p/8456985.html