Energizer Knight
时间限制: 1 Sec 内存限制: 128 MB
题目描述
As previously discussed in the ab Knight problem, a knight is the only piece that can “jump” over pieces. Namely, a typical knight can move 1 square up, down, left or right, followed by 2 squares in a perpendicular direction. Thus, if a knight is at square (x, y), after its jump it can end up at one of these eight positions: (x ± 1, y ± 2), (x ± 2, y ± 1), provided that they are in bounds and there isn’t a piece on the destination square.
An Energizer Knight can make many, many jumps!!! Consider a single knight starting at square (x1 , y1 ) and making exactly k jumps to end up at the target square (x2 , y2 ). Naturally since the knight wants to jump around a lot it’s allowed to hit the same square multiple times, even the starting square and the target square. The only thing that matters is that it ends up at the target square after precisely k consecutive jumps. In a sequence of consecutive jumps, the ending square of the previous jump is the starting square of the subsequent jump.
Typically, there are many paths of length k between any two squares on a standard 8×8 chessboard. For this question, you are asked how many different paths of k consecutive jumps there are between two squares (x1 , y1 ) and (x2 , y2 ). Since the answer to the query can been exceedingly large, you are to give your answer modulo 10007. We model a path as a sequence of locations a0 , a1 , a2 , … ak , where each ai is a location on a standard chess board, a0 = (x1 , y1 ), ak = (x2 , y2 ), and for each i, 0 ≤ i < k, ai → ai+1 represents a valid jump by a knight. Two paths (a0 , a1 , a2 , … ak ), and (b0 , b1 , b2 , … bk ) are considered different if there exists an i such that 0 ≤ i ≤ k, where ai ≠ bi .
The Problem
Given the starting square of a knight (x1 , y1 ), a target square for a knight (x2 , y2 ) and a number of consecutive jumps to perform, calculate the number of different paths the knight could take modulo 10007.
输入
The first line of input will contain a single positive integer, n (n ≤ 20), representing the number of input cases to process. The input cases follow, each on one line. Each case consists of five space separated integers: x1 (1 ≤ x1 ≤ 8), y1 (1 ≤ y1 ≤ 8), x2 (1 ≤ x2 ≤ 8), y2 (1 ≤ y2 ≤ 8), and k (1 ≤ k ≤ 1018 ).
输出
For each case, output a single line with a single integer representing the number of paths of exactly k jumps between the starting and ending squares modulo 10007
样例输入
1 2 3 |
2 2 1 2 5 2 1 1 2 1 3 |
样例输出
1 2 |
2 2 |
题解
题目大意为一个国际象棋中的骑士在棋盘上瞎跳,求从(x1, y1)跳到(x2, y2)步长为k的路径的数量。
预处理:dp[x1][y1][x2][y2][i]为从(x1, y1)跳到(x2, y2)步长为\(2^i\)的路径的数量。
f[x][y][k]表示骑士从起始点k步跳到(x, y)的方案数。k最大为\(10^{18}\),是个极大的数,数组无法开这么大。这时预处理就有用了。对于k,可以将其表示成二进制形式,比如说k可以表示成\(2^{i_1}+2^{i_2}+..+2^{i_m}\)的形式。我们就可以通过预处理的dp数组将f从0步的状态一步步转移到\(2^{i_1}+2^{i_2}+...+2^{i_m}\)(也就是k)的状态。我们用另一个数组g[x][y]记录上一个状态,当g记录的为跳了\(2^{i_1}+2^{i_2}+...+2^{i_{m-1}}\)步的状态时,向跳\(2^{i_1}+2^{i_2}+...+2^{i_m}\)步状态的转移为: f[x2][y2] += g[x1][y1] * dp[x1][y1][x2][y2][m]。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
#include <cstdio> #include <cstring> #include <iostream> #define Mod 10007 using namespace std; const int N = 9; const int M = 63; typedef long long LL; int t; int dp[N][N][N][N][64], f[N][N], g[N][N]; int gx[] = {1, 1, -1, -1, 2, 2, -2, -2}; int gy[] = {2, -2, 2, -2, 1, -1, 1, -1}; void init() { for(int i = 1; i <= 8; i++) for(int j = 1; j <= 8; j++) for(int k = 0; k < 8; k++) { int x = i + gx[k]; int y = j + gy[k]; if(x<1 || x>8 || y<1 || y>8) continue; dp[i][j][x][y][0] = 1; } for(int i = 1; i <= 63; i++) for(int x2 = 1; x2 <= 8; x2++) for(int y2 = 1; y2 <= 8; y2++) for(int x1 = 1; x1 <= 8; x1++) for(int y1 = 1; y1 <= 8; y1++) for(int x3 = 1; x3 <= 8; x3++) for(int y3 = 1; y3 <= 8; y3++) (dp[x1][y1][x3][y3][i] += (dp[x1][y1][x2][y2][i-1] * dp[x2][y2][x3][y3][i-1]) % Mod) %= Mod; } int main(int argc, char const *argv[]) { #ifndef ONLINE_JUDGE freopen("input.in", "r", stdin); freopen("output.out", "w", stdout); #endif init(); scanf("%d", &t); while(t--) { int sx, sy, ex, ey; LL k; scanf("%d%d%d%d%lld", &sx, &sy, &ex, &ey, &k); memset(g, 0, sizeof(g)); memset(f, 0, sizeof(f)); bool flag = 0; for(int i = 0; i <= 63; i++) if((k>>i)&1) { memset(f, 0, sizeof(f)); if(flag) { for(int x1 = 1; x1 <= 8; x1++) for(int y1 = 1; y1 <= 8; y1++) for(int x2 = 1; x2 <= 8; x2++) for(int y2 = 1; y2 <= 8; y2++) (f[x2][y2] += (g[x1][y1] * dp[x1][y1][x2][y2][i]) % Mod) %= Mod; } else { for(int x1 = 1; x1 <= 8; x1++) for(int y1 = 1; y1 <= 8; y1++) f[x1][y1] = dp[sx][sy][x1][y1][i]; flag = 1; } memcpy(g, f, sizeof(g)); } printf("%d\n", f[ex][ey]); } return 0; } |
叨叨几句... NOTHING