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:
The circle always starts from the left upper corner and moves towards lower right.
If the circle touches any edge of the rectangle, it will bounce.
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的正方形,则能划分成 n−1g∗m−1g 个正方形。然后可以发现貌似有规律:每个正方形按照有一个(g-1个,这里g=2)球只经过一次的格子,只有边界上的正方形可能含有两个这样的格子,再给加上。还有就是一开始去掉的行和列上的格子。而这些格子都在边界上,且他们的和为 n−1g+m−1g 。如下图所示
因此可以得到公式:ans= n−1g+m−1g+(g−1)∗n−1g∗m−1g
进一步的理解(为什么一个单元正方形含有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;
}