【[Offer收割]编程练习赛13 D】骑士游历(矩阵快速幂模板)

来源:互联网 发布:vim教程 知乎 编辑:程序博客网 时间:2024/06/09 17:13

题目:http://hihocoder.com/problemset/problem/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的余数。

分析:

对于棋盘中任意一个点(R,C),都有多个位置可跳。

比如:(R,C)可以跳到(R+1,C+2)的位置。

为了描述这种关系,可以建立一个64x64的邻接矩阵;这个邻接矩阵第一维对应8X8中的每一个点,第二维维护第一维的点可跳的位置。

对于这样的一个矩阵,用起始矩阵1X64乘以邻接矩阵64X64,得到的一个1X64的矩阵,这个矩阵的点上值表示从起始位置走一步,到达该位置有多少中方案。(参考离散数学和线性代数)

因此可以将这个乘以矩阵的过程转化为矩阵快速幂,迅速求得结果。

copy自:http://www.cnblogs.com/aiterator/p/6685932.html
话说用vector实现矩阵快速幂还挺清爽的,以后就这样用了。

代码:

#include<bits/stdc++.h>using namespace std;typedef vector<unsigned long long> vec;typedef vector<vec> mat;const unsigned long long mod = 1000000007;int dir[8][2] = { {1, 2}, {1, -2}, {-1, 2}, {-1, -2}, {2, 1}, {2, -1}, {-2, 1}, {-2, -1} };mat mul(mat &a, mat &b){    mat c(a.size(), vec(b[0].size(), 0));    for(int i=0; i<a.size(); ++ i)    {        for(int j=0; j<b[0].size(); ++ j)        {            for(int k=0; k<b.size(); ++ k)                c[i][j] = (c[i][j] + a[i][k] * b[k][j]) % mod;        }    }    return c;}mat pow(mat &a, unsigned long long n){    mat b(a.size(), vec(a[0].size(), 0));    for(int i=0; i<a.size(); ++ i)        b[i][i] = 1;    while(n > 0)    {        if(n & 1)            b = mul(b, a);        a = mul(a, a);        n >>= 1;    }    return b;}int main(){    int n, r, c;    cin >> n >> r >> c;    mat a(64, vec(64, 0));    for(int i=0; i<8; ++ i)    {        for(int j=0; j<8; ++ j)        {            for(int k=0; k<8; ++ k)            {                int x = i + dir[k][0], y = j + dir[k][1];                if((x >= 0 && x < 8 && y >= 0 && y < 8) == false)                    continue;                int u = x * 8 + y, v = i * 8 + j;                a[u][v] = a[v][u] = 1;            }        }    }    mat b(1, vec(64, 0));    b[0][(r-1)*8 + c-1] = 1;    mat s = pow(a, n);    mat d = mul(b, s);    unsigned long long ans = 0;    for(auto &i: d)    {        for(auto &j: i)            ans = (ans + j) % mod;    }    cout << ans << endl;    return 0;}
0 0
原创粉丝点击