NOIP2018提高组金牌训练营——数论专题

1187 寻找分数

给出 a,b,c,d, 找一个分数p/q,使得a/b < p/q < c/d,并且q最小。例如:1/3同1/2之间,符合条件且分母最小的分数是2/5。(如果q相同,输出p最小的)
 
Input
第1行:一个数T,表示后面用作输入测试的数的数量。(1 <= T <= 10000)
第2 - T + 1行:每行4个数,a,b,c,d,中间用空格分隔。(1 <= a,b,c,d <= 10^9)
Output
输出共T行,对应符合条件的分数。
Input示例
4
1 3 1 2
2 1 3 1
2 1 4 1
1000 1001 1001 1002
Output示例
2/5
5/2
3/1
2001/2003



一开始想到二分q,因为q越大显然选择越多(其实是错的)
有了q之后设p=1
可以用lcm把三个式子的分母通分,得到分子
然后可以找在新的分子中存不存在a<p<c

写完后发现过不了样例
然后发现有极少极少的数不满足单调性,大部分都是满足的
但是这样就不能二分了
怎么办??
我直接枚举,非常暴力。
我想着应该会超时
我一交上去
我靠25个点过了22个点
3个点没过是因为WA,最后一个点900多毫秒,卡过去了
其实考试这样的话我就满意了
然后我觉得没过是因为取lcm的时候会爆long long
我就改成了unsigned long long
多过了一个点。
写高精度??
不行,这样就会超时。
所以这就是我这种做法的极限了,25个点能过23个点
#include<bits/stdc++.h>
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std;

typedef unsigned long long ull;
ull a, b, c, d;
ull ansp, ansq;

ull gcd(ull a, ull b) { return !b ? a : gcd(b, a % b); }
ull lcm(ull a, ull b) { return a / gcd(a, b) * b; }

bool check(ull q)
{
    ull t = lcm(lcm(b, q), d);
    ull p = t / q, ta = t / b * a, tc = t / d * c;
    t = ta / p + 1;
    if(ta < t * p && t * p < tc) 
    {
        ansp = t;
        ansq = q;
        return true;
    }
    return false;
}

int main()
{
    int T;
    scanf("%d", &T);
    
    while(T--)
    {
        scanf("%llu%llu%llu%llu", &a, &b, &c, &d);
        
        ull t = gcd(a, b);
        a /= t; b /= t;
        t = gcd(c, d);
        c /= t; d /= t;    
        
        for(register ull ans = 1; ; ans++)
            if(check(ans))
            {
                printf("%llu/%llu\n", ansp, ansq);
                break;
            }
    } 
    
    return 0;
}

我们来讲一下正解

待补……

猜你喜欢

转载自www.cnblogs.com/sugewud/p/9832145.html