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