小红走网格
思路
小红从原点 (0,0) 出发,每次可以向上走 a 步、向下走 b 步、向左走 c 步、向右走 d 步,问能否到达 (x, y)。
把 x 和 y 两个方向拆开独立考虑:
- x 方向:向右走 r 次、向左走 s 次,最终 x 坐标 = rd - sc,其中 r, s >= 0。
- y 方向:向上走 p 次、向下走 q 次,最终 y 坐标 = pa - qb,其中 p, q >= 0。
关键数学结论:对于非负整数 r, s,rd - sc 能表示的整数集合恰好是 gcd(c, d) 的所有倍数。
为什么?由裴蜀定理,存在整数 r', s' 使得 r'd + s'c = gcd(c, d),因此 gcd(c, d) 的任意倍数都能用 d 和 c 的整数线性组合表示。虽然裴蜀定理的解可能有负数,但只要给 r' 和 s' 分别加上足够大的 c 和 d 的倍数,就能把它们都调成非负的(总值不变,因为加的是 cd - dc = 0)。
所以判定条件很简单:
- x % gcd(c, d) == 0 且 y % gcd(a, b) == 0 就输出 YES,否则 NO。
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
int T;
scanf("%d", &T);
while (T--) {
long long x, y, a, b, c, d;
scanf("%lld%lld%lld%lld%lld%lld", &x, &y, &a, &b, &c, &d);
long long gx = __gcd(c, d);
long long gy = __gcd(a, b);
puts(x % gx == 0 && y % gy == 0 ? "YES" : "NO");
}
return 0;
}
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int T = Integer.parseInt(br.readLine().trim());
StringBuilder sb = new StringBuilder();
while (T-- > 0) {
StringTokenizer st = new StringTokenizer(br.readLine());
long x = Long.parseLong(st.nextToken());
long y = Long.parseLong(st.nextToken());
long a = Long.parseLong(st.nextToken());
long b = Long.parseLong(st.nextToken());
long c = Long.parseLong(st.nextToken());
long d = Long.parseLong(st.nextToken());
long gx = gcd(c, d);
long gy = gcd(a, b);
sb.append(x % gx == 0 && y % gy == 0 ? "YES" : "NO").append('\n');
}
System.out.print(sb);
}
static long gcd(long a, long b) {
a = Math.abs(a); b = Math.abs(b);
while (b != 0) { long t = b; b = a % b; a = t; }
return a;
}
}
import sys
import math
input = sys.stdin.readline
def main():
t = int(input())
out = []
for _ in range(t):
x, y, a, b, c, d = map(int, input().split())
gx = math.gcd(c, d)
gy = math.gcd(a, b)
out.append("YES" if x % gx == 0 and y % gy == 0 else "NO")
print('\n'.join(out))
main()
const readline = require('readline');
const rl = readline.createInterface({ input: process.stdin });
const lines = [];
rl.on('line', line => lines.push(line));
rl.on('close', () => {
function gcd(a, b) {
if (a < 0n) a = -a;
if (b < 0n) b = -b;
while (b !== 0n) { let t = b; b = a % b; a = t; }
return a;
}
let idx = 0;
const T = parseInt(lines[idx++]);
const out = [];
for (let i = 0; i < T; i++) {
const parts = lines[idx++].trim().split(/\s+/);
const x = BigInt(parts[0]);
const y = BigInt(parts[1]);
const a = BigInt(parts[2]);
const b = BigInt(parts[3]);
const c = BigInt(parts[4]);
const d = BigInt(parts[5]);
const gx = gcd(c, d);
const gy = gcd(a, b);
out.push(x % gx === 0n && y % gy === 0n ? "YES" : "NO");
}
console.log(out.join('\n'));
});
复杂度分析
- 时间复杂度:
,每组数据做两次 GCD 计算。
- 空间复杂度:
,只用常数变量。
小结
这道题的核心是把二维问题拆成两个独立的一维问题,然后用裴蜀定理判断可达性。rd - sc(r, s 非负)能表示的值恰好是 gcd(c, d) 的所有整数倍,因此只需判断 x 和 y 分别能否被对应方向步长的 GCD 整除即可。



京公网安备 11010502036488号