题目链接

墙壁划线

题目描述

一面矩形墙壁由 块完全一致的瓷砖铺成,每块瓷砖尺寸为 。现在从墙的左上角到右下角、右上角到左下角各画一条直线。 请求出这两条直线与所有瓷砖边界线(包括墙壁的边界)形成的交点总数。

输入:

  • 一行输入四个正整数

输出:

  • 输出一个整数,表示交点总数。

解题思路

这是一个典型的几何计数问题,核心是利用容斥原理计算不同交点的数量。

首先,一个关键的观察是:瓷砖的具体尺寸 不影响交点的数量。交点的数量仅取决于墙壁由多少块瓷砖组成,即 的值。因为对角线方程与瓷砖边界方程求解交点时, 因子可以被约去,交点模式只和 的比例有关。因此,我们可以忽略输入中的

我们的目标是计算两条对角线与网格线(瓷砖边界)交点的并集大小。设 为第一条对角线(左上到右下)与网格线的交点集合, 为第二条对角线(右上到左下)的交点集合。我们要求的就是 。 根据容斥原理:

  1. 计算单条对角线的交点数

    • 一面 的瓷砖墙,有 条垂直网格线和 条水平网格线(包括边界)。
    • 一条对角线会穿过这些网格线形成交点。如果它直接穿过一个网格顶点(横线和竖线的交点),那么这个点只算一个交点。
    • 一条从 的对角线穿过的网格顶点数(不含起点终点)为 。算上起点和终点,共穿过 个顶点。
    • 使用容斥原理计算单条对角线的交点数:
  2. 计算

    • 由于对称性,
  3. 计算两条对角线共同的交点数

    • 两条对角线唯一的交点是矩形墙壁的中心点。
    • 只有当这个中心点恰好落在某条网格线上时,它才会被我们计入
    • 墙壁的中心点坐标可以表示为 (以瓷砖数为单位)。
    • 这个点落在垂直网格线上,当且仅当 是偶数。
    • 这个点落在水平网格线上,当且仅当 是偶数。
    • 因此,只要 中至少有一个是偶数,中心点就会落在网格线上,并被重复计算。此时
    • 如果 都是奇数,中心点不在任何网格线上,
  4. 汇总

    • 将上述结果代入总公式,得到最终交点数:

代码

#include <iostream>
#include <numeric>

using namespace std;
using LL = long long;

LL gcd(LL a, LL b) {
    return b == 0 ? a : gcd(b, a % b);
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    LL a, b, x, y;
    cin >> a >> b >> x >> y;
    
    LL total_points = 2 * (a + b + 1 - gcd(a, b));
    if (a % 2 == 0 || b % 2 == 0) {
        total_points--;
    }
    
    cout << total_points << endl;
    
    return 0;
}
import java.util.Scanner;

public class Main {
    static long gcd(long a, long b) {
        return b == 0 ? a : gcd(b, a % b);
    }
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        long a = sc.nextLong();
        long b = sc.nextLong();
        long x = sc.nextLong();
        long y = sc.nextLong();
        
        long total_points = 2 * (a + b + 1 - gcd(a, b));
        if (a % 2 == 0 || b % 2 == 0) {
            total_points--;
        }
        
        System.out.println(total_points);
    }
}
import math

def gcd(a, b):
    return math.gcd(a, b)

a, b, x, y = map(int, input().split())

total_points = 2 * (a + b + 1 - gcd(a, b))
if a % 2 == 0 or b % 2 == 0:
    total_points -= 1

print(total_points)

算法及复杂度

  • 算法:数学、容斥原理、最大公约数(GCD)
  • 时间复杂度:,主要开销来自计算最大公约数。
  • 空间复杂度: