hihoCoder1584

#1584 : Bounce

时间限制: 1000ms
单点时限: 1000ms
内存限制: 256MB

描述

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).

样例输入
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

题意:一个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);
	}
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值