17icpc北京网络赛G题(gcd意义)

本文探讨了在一个N×M网格组成的矩形中,一个圆从左上角开始朝右下角弹跳直至到达另一角落的路径问题。通过数学分析得出,圆在达到矩形的另一角落之前会恰好经过多少个单元格。文中提供了详细的思路解析及C++代码实现。
摘要由CSDN通过智能技术生成

problem

For Argo, it is very interesting watching a circle bouncing in a rectangle.

As shown in the figure below, the rectangle is divided into N×M grids, and the circle fits exactly one grid.

The bouncing rule is simple:

  1. The circle always starts from the left upper corner and moves towards lower right.

  2. If the circle touches any edge of the rectangle, it will bounce.

  3. If the circle reaches any corner of the rectangle after starting, it will stop there.

Argo wants to know how many grids the circle will go through only once until it first reaches another corner. Can you help him?

输入

The input consists of multiple test cases. (Up to 10^5)

For each test case:

One line contains two integers N and M, indicating the number of rows and columns of the rectangle. (2 ≤ N, M ≤ 10^9)

输出

For each test case, output one line containing one integer, the number of grids that the circle will go through exactly once until it stops (the starting grid and the ending grid also count).

样例输入

2 2
2 3
3 4
3 5
4 5
4 6
4 7
5 6
5 7
9 15

样例输出

2
3
5
5
7
8
7
9
11
39


思路

首先应注意到这样一个性质:
要想再回到顶角,竖直方向上经过的格子是p * (n-1), 水平方向上经过的格子是q * (m-1),其中p,q为整数。
理解:以水平方向为例,当球从左到右壁反弹时,水平方向走了一个n-1,再回去后,到左壁右走了n-1,而最终要求到顶角(左壁或右壁),即q*(m-1)。同理,竖直方向为p * (n-1)。


由上面推理知n-1,m-1在这里很重要。我们根据样例图规律,去除左上角的行和列,对剩下的(n-1)*(m-1)个格子进行划分。令 g=GCD(n-1,m-1),划分的最小单元为g*g的正方形,则能划分成 n1gm1g 个正方形。然后可以发现貌似有规律:每个正方形按照有一个(g-1个,这里g=2)球只经过一次的格子,只有边界上的正方形可能含有两个这样的格子,再给加上。还有就是一开始去掉的行和列上的格子。而这些格子都在边界上,且他们的和为 n1g+m1g 。如下图所示

这里写图片描述


因此可以得到公式:ans= n1g+m1g+(g1)n1gm1g


进一步的理解(为什么一个单元正方形含有g-1个只经过一次的格子),可以考虑对偶图


代码示例

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

ll gcd(ll m,ll n)
{
    if(n==0) return m;
    return gcd(n,m%n);
}

int main()
{
    //ios::sync_with_stdio(false);
    //freopen("read.txt","r",stdin);
    ll n,m;
    while(cin>>n>>m)
    {
        ll g=gcd(n-1,m-1);
        cout<<(n-1)/g+(m-1)/g+(g-1)*((n-1)/g*(m-1)/g)<<endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值