codeforces#328-C - The Big Race-乘法溢出解决办法之一 + lcm/gcd+数学

题意:http://codeforces.com/contest/592/problem/C

给出n, 你可以设置跑道长度为 1-n,  

选手1 每次一定要前进w步,选手2是b步

让选手1和选手2  做 任意次前进,要求最后离终点步数 选手1不超过w,选手2不超过b  (其实就是 离终点n%b,n%w)

问如何设置跑到长度,使得最终两个人停下来时,离终点的距离是一样的?  (求1-n多少个数是合法的)

输出   (合法的个数/n)最简分数形式



首先当n足够长,每一个lcm(w,b)必然出现 min(w,b)个长度 使得他们满足要求

那么总共 n/lcm(w,b) 个是合法的,    

【余数计算部分】然后就是  res=n%lcm(w,b)  这最后余数这段。。。。。。


如果min(w,b)<res那么  ans就要加上 min(w,b)-1   (为什么减一,因为 最后一个合法的数  是lcm(w,b)中最后面的一个数,显然res娶不到这个数)

反之,  min(w,b)>res,说明res 里面的数都是满足条件的 都取上。。。。


这题唯一的大坑是,数据范围全是LL。。。。。在开始求lcm 直接相乘会溢出,当然可以用高精度解决;


这里用的是  把乘法变成加法。。。。 把w*b 转成 w个b相加。。。当加到 的值超过长度n时,说明必然lcm>n  就直接跳到 【余数计算部分】

..

那么ans就是 an=min(w-1,n);   (这里的w 是w,b中较小的一个)

然后 ans= an/n (的最简分数形式)


ac代码:




#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <queue>
#include <map>
#include <bitset>
#include <vector>
using namespace std; 
__int64 min(__int64 a,__int64 b)
{
	return a<b?a:b;
}

__int64 gcd(__int64 a,__int64 b){  
    if(b==0)  
        return a;   
	return gcd(b,a%b);  
}  
 
int main()
{
	
__int64		out(__int64 x,__int64 n);
	
	__int64 n,w,b;
	scanf("%I64d%I64d%I64d",&n,&w,&b);
	
int ok=0;
	if (w>b) swap(w,b);
	else if (w==b) {printf("1/1\n");return 0;}   
 
		__int64 hh=0;
		__int64 hw=w/gcd(w,b);  //求最小公倍数要除去一个最大公约数。。
		while(hw--)			//用累加来判断是否有乘法溢出
		{
			hh+=b;
			if (hh>n)
			{
				ok=1;
				break;
			}
		}
		if (ok)			//如果会溢出,那么说明最小公倍数都大于长度N,所以 答案必然是 小的w-1或者是n
		{
			__int64 an=min(w-1,n);
			if (an==0) printf("0/1");
			else
			{
				__int64 gd=gcd(an,n);
				printf("%I64d/%I64d\n",an/gd,n/gd);
			}
			return 0;
		}
	 
					//以下情况是没有乘法溢出的		
	__int64 gg=b/gcd(w,b)*w;		//lcm
	__int64 tmp=(n)/gg;					//多少个完整的lcm
	__int64 minn=min(w,b);				//取小的那个
	__int64 ans=tmp*(minn);

  
	__int64 t1=n-tmp*gg;			
	__int64 t2=n-tmp*gg; 
	__int64 need; 
	need=min(t1,t2);			
	 if (need>=minn-1)			//如果去掉所有完整的lcm后,剩下的长度为ll   答案为min(ll,minn-1); 
	 {
		 ans+=minn-1;
	 }else
		 ans+=need;			
	
	
	out(ans,n);			
	
	return 0;
	
}

__int64	 out(__int64 x,__int64 n)
{
	__int64 tmp=gcd(x,n);
	printf("%I64d/%I64d\n",x/tmp,n/tmp);
	return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值