[Offer收割]编程练习赛13 hihocoder 1504 (矩阵快速幂)

#1504 : 骑士游历

时间限制: 10000ms
单点时限: 1000ms
内存限制: 256MB

描述

在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

题目链接:https://hihocoder.com/problemset/problem/1504

题目分析:典型的矩阵快速幂问题,由于棋盘大小只有8*8,可以将一个点的横纵坐标hash成一个值,建一个64*64的矩阵来表示点的转移

import java.util.*;
import java.io.*;

public class Main {

    public static final long MOD = 1000000007;
    public static final int CON = 64;
    public static int[] dx = {1, 2, 2, 1, -1, -2, -2, -1};
    public static int[] dy = {-2, -1, 1, 2, 2, 1, -1, -2};
    public static int n, r, c;

    static class myScanner {
        public BufferedReader br;
        public StringTokenizer st;

        public myScanner(InputStream in) {
            br = new BufferedReader(new InputStreamReader(in));
            st = new StringTokenizer("");
        }

        public String nextLine() {
            try {
                return br.readLine();
            } catch(IOException e) {
                return null;
            }
        }

        public boolean hasNext() {
            while(!st.hasMoreTokens()) {
                String s = nextLine();
                if (s == null) {
                    return false;
                }
                st = new StringTokenizer(s);
            }
            return true;
        }

        public String next() {
            hasNext();
            return st.nextToken();
        }

        public int nextInt() {
            return Integer.parseInt(next());
        }
    }

    static class Matrix {
        public int n, m;
        public long[][] mat;

        public Matrix(int n, int m) {
            this.n = n;
            this.m = n;
            mat = new long[n][m];
            for (int i = 0; i < n; i ++) {
                Arrays.fill(mat[i], 0);
            }
        }

        public static Matrix mul(Matrix a, Matrix b) {
            Matrix ans = new Matrix(a.n, b.m);
            for (int i = 0; i < a.n; i ++) {
                for (int j = 0; j < b.m; j ++) {
                    for (int k = 0; k < a.m; k ++) {
                        ans.mat[i][j] = (ans.mat[i][j] + a.mat[i][k] * b.mat[k][j]) % MOD;
                    }
                }
            }
            return ans;
        }

        public static Matrix pow(Matrix a, int n) {
            Matrix ans = new Matrix(a.n, a.n);
            for (int i = 0; i < a.n; i ++) {
                ans.mat[i][i] = 1;
            }
            while (n != 0) {
                if ((n & 1) == 1) {
                    ans = mul(ans, a);
                }
                a = mul(a, a);
                n >>= 1;
            }

            return ans;
        }
    } 

    public static Matrix pre() {
        Matrix ans = new Matrix(64, 64);
        for (int i = 0; i < 8; i ++) {
            for (int j = 0; j < 8; j ++) {
                for (int k = 0; k < 8; k ++) {
                    int x = i + dx[k];
                    int y = j + dy[k];
                    if (x < 0 || y < 0 || x > 7 || y > 7) {
                        continue;
                    }
                    ans.mat[i * 8 + j][x * 8 + y] = 1;
                }
            }
        }
        return ans;
    }

    public static void main(String[] args) {
        myScanner in = new myScanner(System.in);
        n = in.nextInt();
        r = in.nextInt();
        c = in.nextInt();
        r --;
        c --;
        Matrix coef = pre();
        Matrix ans = new Matrix(64, 64);
        ans.mat[r * 8 + c][r * 8 + c] = 1;
        ans = Matrix.mul(ans, Matrix.pow(coef, n));
        long res = 0;
        for (int i = 0; i < 64; i ++) {
            for (int j = 0; j < 64; j ++) {
                res = (res + ans.mat[i][j]) % MOD;
            }
        }
        System.out.println(res);
    }
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值