A chess Problem
描述
In chinese chess, “马” is an interesting piece, when it is at position (x,y) ( x , y ) , it can move to (x−2,y−1),(x−2,y+1),(x−1,y−2),(x−1,y+2),(x+1,y−2),(x+1,y+2),(x+2,y−1),(x+2,y+1) ( x − 2 , y − 1 ) , ( x − 2 , y + 1 ) , ( x − 1 , y − 2 ) , ( x − 1 , y + 2 ) , ( x + 1 , y − 2 ) , ( x + 1 , y + 2 ) , ( x + 2 , y − 1 ) , ( x + 2 , y + 1 ) ,
Now the problem is, when a “马” is at position (x,y), how many ways does it have for he to move to (x0,y0). ( x 0 , y 0 ) .
To simplify this problem, when our “马” is at (x,y), it can only move to (x+1,y+2)or(x+2,y+1) ( x + 1 , y + 2 ) o r ( x + 2 , y + 1 )
easy输入
The first line: the number of case T(≤T≤100)
Then T lines follow, each line contains four integers: x,y,x0,y0(0≤x,y,x0,y0≤8) - the position the “马” at and the position it want’s to go.
easy输出
For each case, out put an integer ans one line – the number of the ways to go from (x,y) to (x0,y0)
medium输入
The first line: the number of case T(≤T≤1000)
Then T lines follow, each line contains four integers: x,y,x0,y0(0≤x,y,x0,y0≤100000) - the position the “马” at and the position it want’s to go.
medium输出
For each case, out put an integer ans one line – the number of the ways to go from (x,y) to (x0,y0) mod 109+7
hard输入
The first line: the number of case T(≤T≤1000)
Then T lines follow, each line contains four integers: x,y,x0,y0(0≤x,y,x0,y0≤10000000) - the position the “马” at and the position it want’s to go.
hard输出
For each case, out put an integer ans one line – the number of the ways to go from (x,y) to (x0,y0) mod 104+7
样例输入1
3
0 0 3 3
0 0 6 6
3 3 6 6
样例输出1
2
6
2
提示
In the first example:
(0,0)−>(2,1)−>(3,3),(0,0)−>(1,2)−>(3,3)
In the second example:
(0,0)−>(2,1)−>(4,2)−>(5,4)−>(6,6),(0,0)−>(2,1)−>(3,3)−>(5,4)−>(6,6)
(0,0)−>(2,1)−>(3,3)−>(4,5)−>(6,6),(0,0)−>(1,2)−>(3,3)−>(5,4)−>(6,6)
(0,0)−>(1,2)−>(3,3)−>(4,5)−>(6,6),(0,0)−>(1,2)−>(2,4)−>(4,5)−>(6,6)
In the third example:
(3,3)−>(5,4)−>(6,6),(3,3)−>(4,5)−>(6,6)
题意:给你一个棋盘,难度不同,大小不同,给你起点和终点,问你有多少种方式可以从起点到达终点,你当前只能有两个位置可以走,假设你在
(x,y),你只能走到(x+2,y+1)或(x+1,y+2)
(
x
,
y
)
,
你
只
能
走
到
(
x
+
2
,
y
+
1
)
或
(
x
+
1
,
y
+
2
)
。
分析:首先是easy,直接递归即可,范围很小, 主要说下medium和hard,我们可以通过平移使得起点始终为
(0,0)点
(
0
,
0
)
点
,所以我们只需考虑起点在
(0,0)
(
0
,
0
)
即可,详见下图
根据上图,绿色区域为“马”能走到的坐标,首先可以确定的是,2,3,4,6,7,10,11,15,16,21
只能够到达一次,比如5
,可以从2
或3
坐标到达,而8
,可以从4
或5
到达,12
可以从7
或8
到达,现在应该可以找到规律了,如果把整体右旋
135o
135
o
,就变成熟悉的杨辉三角,比如8
坐标能到达的方案即为“:
C34
C
4
3
,到这点了还不够,比如
Ckn
C
n
k
,我们怎么确定n和k
呢,见下图
我们先将一点平移至
(0,0)点,另一点记为:(x′+y′)
(
0
,
0
)
点
,
另
一
点
记
为
:
(
x
′
+
y
′
)
,然后将能到达的坐标延长后,发现
(x′+y′)
(
x
′
+
y
′
)
%3==0)
%
3
==
0
)
,先通过这一条件把一些点特判掉,然后还有延长线中到达不了的,特判掉即可
,我们找到此规律后就好办了,首先是medium,直接预处理出1e5
的阶乘(取模后),然后有图找到相应的
Ckn
C
n
k
即可,hard里我们利用Lucas可以快速求大整数取模,详见代码
参考代码
// medium
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <map>
using namespace std;
const int maxn = 1e5 + 10;
const int MOD = 1e9 + 7;
typedef long long ll;
#define mod(x) ((x) % MOD)
ll qpow(ll a,ll b) {
ll res = 1;
while (b) {
if(b & 1) {
res = mod(res * a);
}
a = mod(a * a);
b >>= 1;
}
return res;
}
ll x,y,xx,yy;
ll fac[maxn], rfac[maxn];
void init() {
fac[0] = 1;
for (int i = 1; i <= maxn; i++)
fac[i] = mod(fac[i - 1] * i);
rfac[maxn] = qpow(fac[maxn],MOD - 2);
for (int i = maxn;i > 0; i--)
rfac[i - 1] = mod(rfac[i] * i);
}
int main(){
int T; cin>>T;
init();
while (T--) {
cin>>x>>y>>xx>>yy;
ll ex = xx - x;
ll ey = yy - y;
if(ex <= 0 || ey <= 0 || (ex + ey) % 3 != 0) {
puts("0");
} else {
ll t = (ex + ey) / 3;
ll bo = t;
ll up = t + t;
if(ey < bo || ey > up) {
puts("0");
} else {
ll k = ey - t;
ll n = t;
cout<<mod(fac[n] * 1ll*mod(rfac[k]*1ll*rfac[n - k]))<<endl;
}
}
}
return 0;
}
参考代码
// hard
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <map>
using namespace std;
const int maxn = 1e5 + 7;
const int MOD = 1e4 + 7;
typedef long long ll;
#define mod(x) ((x) % MOD)
ll qpow(ll a,ll b) {
ll res = 1;
while (b) {
if(b & 1) {
res = mod(res * a);
}
a = mod(a * a);
b >>= 1;
}
return res;
}
ll x,y,xx,yy;
ll C(ll nn, ll mm) {
ll up = 1, down = 1;
for (int i = nn - mm + 1; i <= nn; i++) up = mod(up * 1ll *i);
for (int i = 1; i <= mm; i++) down = mod(down * 1ll *i);
return mod(up * qpow(down, MOD - 2));
}
ll lucas(ll n, ll m) {
if(m == 0) return 1;
return mod(lucas(n / MOD, m / MOD) * 1ll * C(n % MOD,m % MOD));
}
int main(){
int T; cin>>T;
while (T--) {
cin>>x>>y>>xx>>yy;
ll ex = xx - x;
ll ey = yy - y;
if(ex <= 0 || ey <= 0 || (ex + ey) % 3 != 0) {
puts("0");
} else {
ll t = (ex + ey) / 3;
ll bo = t;
ll up = t + t;
if(ey < bo || ey > up) {
puts("0");
} else {
ll k = ey - t;
ll n = t;
cout<<lucas(n,k)<<endl;
}
}
}
return 0;
}