#1584 : Bounce
-
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
描述
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 105)
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 ≤ 109)
输出
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).
题意:一个n*m的矩阵,一束光从左上角出发45°入射,并在矩阵内不断反射直到进入一个角落而停止,求出光线经过且仅经过一次的矩阵点的个数。
思路:这题主要是找出光线组成最小正方形个数及边长,由边长即可求出个数,所以先求出边长,这个最小正方形边长可由矩阵高度及形成的一个较小的正方形边长的最大公倍数求得。接下来就是分类讨论(比赛的时候死活没想出来。。。)
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
using namespace std;
long long n,m;
long long gcd(long long a,long long b)
{
if(b==0)return a;
return gcd(b,a%b);
}
int main()
{
while(~scanf("%lld%lld",&n,&m))
{
if(n>m)swap(n,m); //n为高 ,m为宽
long long x=(m-1)%(n-1);
if(x==0) //没有光线重叠出去
{
printf("%lld\n",m);
continue;
}
x++; //求出一种边长
if(n-(x-1)<x) //在两种边长中找到较小的一个
{
x=n-(x-1);
}
x=gcd(n-1,x-1)+1; //通过gcd求得最小正方形边长
long long r,c;
// cout<<"xxxx "<<x<<endl;
r=(n-1)/(2*x-2); //最小正方形有r行
c=(m-1)/(2*x-2); // 最小正方形有c列
// cout<<"asahahh"<<endl;
long long ans=(4*x-4)*r*c-2*c*(r-1)-2*r*(c-1); //求出这些张方形所占据的点的个数,去除掉经过多次的
// cout<<"xrcans "<<x<<" "<<r<<" "<<c<<" "<<ans<<endl;
if(r==1&&c==1) //只有一个正方形
{
ans+=(2*(x-1)-1);
}
else if((n-1)%(2*x-2)==x-1&&((m-1)%(2*x-2)!=x-1)) //还能增加一行小正方形
{
ans+=((2*x-3)*(c-1)-c);
// cout<<"plus1 "<<((2*x-3)*(c-1)-c)<<endl;
ans+=(2*(x-1));
}
else if((n-1)%(2*x-2)!=x-1&&((m-1)%(2*x-2)==x-1)) //还能增加一列小正方形
{
ans+=((2*x-3)*(r-1)-r);
// cout<<"plus2 "<<((2*x-3)*(r-1)-r)<<endl;
ans+=(2*(x-1));
}
else if((n-1)%(2*x-2)==x-1&&((m-1)%(2*x-2)==x-1)) //还能再一行加一列小正方形,接壤处处理一下
{
ans+=((2*x-3)*(c-1)-c);
ans+=((2*x-3)*(r-1)-r);
ans+=(3*x-4);
// cout<<"plus3 "<<((2*x-3)*(r-1)-r)+((2*x-3)*(r-1)-r)+(3*x-4)<<endl;
ans+=(2*(x-1));
}
else //没有小正方形能增加
{
ans+=(2*(x-1)-2);
}
printf("%lld\n",ans);
}
}