wkroach is dream knight(矩阵快速幂)

链接:https://ac.nowcoder.com/acm/contest/554/D
来源:牛客网
 

题目描述

wkroach明天终于要去和那个女孩见面了,这天晚上在梦中他变成了一名骑士,然而wkroach毕竟是理工男,他变成的是棋盘上骑士,在梦醒之前他有N步移动的机会,wkroach想知道他总共可能有多少种走法呢。
这是一个8*8的棋盘,wkroach有一个初始位置,每次移动不能超出棋盘并且必须遵循骑士行走的规则也就和中国象棋的“马”类似但是不存在“蹩马腿”,如果你二者的规则都不知道那就看下一题吧)

输入描述:

第一行输入一个正整数T代表测试样例数目
每组样例有三个正整数N R C(0<n<1000000000,0<R<9,0<C<9)代表此样例步数N及wkroach的初始点(R,C)。

输出描述:

对于每组测试数据,输出一个整数,表示总走法数。

思路:定义a[i][j]为地图,第i,j表示位置,给每个位置付一个值,然后定义64*64的矩阵,将i,j,能到达的位置放进vector里。

算了,具体看代码。

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define mem(ar,num) memset(ar,num,sizeof(ar))
#define me(ar) memset(ar,0,sizeof(ar))
#define lowbit(x) (x&(-x))
#define IOS ios::sync_with_stdio(false)
#define DEBUG cout<<endl<<"DEBUG"<<endl;
using namespace std;
const int mod = 1e9 + 7;
ll t, n, r, c;
struct mtx {
    ll x[64 + 1][64 + 1];
    mtx() {
        memset(x, 0, sizeof x);
    }
} ans;
mtx operator *(const mtx &a, const mtx &b) {
    mtx c;
    for(int i = 0; i < 64; i++)
        for(int j = 0; j < 64; j++)
            for(int k = 0; k < 64; k++)
                c.x[i][j] = (c.x[i][j] + a.x[i][k] * b.x[k][j] % mod) % mod;
    return c;
}
mtx operator ^(mtx a, ll k) {
    mtx ret;
    for(int i = 0; i < 64; ++i)
        ret.x[i][i] = 1;
    while(k) {
        if(k & 1)
            ret = ret * a;
        a = a * a;
        k >>= 1;
    }
    return ret;
}
int o[9][9], bb;
vector<int>v[100];
int main() {
    cin >> t;
    for(int i = 0; i < 8; i++)
        for(int j = 0; j < 8; j++)
            o[i][j] = bb++;
    for(int i = 0; i < 8; i++) {
        for(int j = 0; j < 8; j++) {
            int k = o[i][j];
            if((i + 2) < 8 && (j + 1) < 8)
                v[k].push_back(o[i + 2][j + 1]);
            if((i + 1) < 8 && (j + 2) < 8)
                v[k].push_back(o[i + 1][j + 2]);
            if((i - 1) >= 0 && (j - 2) >= 0)
                v[k].push_back(o[i - 1][j - 2]);
            if((i - 2) >= 0 && (j - 1) >= 0)
                v[k].push_back(o[i - 2][j - 1]);
            if((i - 2) >= 0 && (j + 1) < 8)
                v[k].push_back(o[i - 2][j + 1]);
            if((i - 1) >= 0 && (j + 2) < 8)
                v[k].push_back(o[i - 1][j + 2]);
            if((i + 1) < 8 && (j - 2) >= 0)
                v[k].push_back(o[i + 1][j - 2]);
            if((i + 2) < 8 && (j - 1) >= 0)
                v[k].push_back(o[i + 2][j - 1]);
        }
    }
    while(t--) {
        cin >> n >> r >> c;
        mtx ak;
        for(int i = 0; i < 64; i++)
            for(int j = 0; j < v[i].size(); j++)
                ak.x[i][v[i][j]] = 1;
        int ans = 0;
        mtx w = ak ^ n;//走n步
        int k = o[r-1][c-1];//记得减一,debug好久
        for(int i = 0; i < 64; i++) {
            ans += w.x[k][i];//将k能到达的位置加起来。
            ans %= mod;
        }
        cout << ans << endl;
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值