【2020年牛客暑假第三场】F题 Fraction Construction Problem

【2020年牛客暑假第三场】F题 Fraction Construction Problem--gcd、扩展欧几里得

    • 思路
    • Code

题目链接:https://ac.nowcoder.com/acm/contest/5668/F

题目描述
There are t queries.
In each query, you are given two positive integers a a a and b b b ( a , b ≤ 2 × 1 0 6 ) (a, b\leq2×10^6) (a,b2×106)
Please print a line consists of four positive integers c , d , e , f c,d,e,f c,d,e,fsatisfying the following constraints:

  • c d − e f = a b \frac{c}{d}-\frac{e}{f}=\frac{a}{b} dcfe=ba
  • d < b d < b d<b and f < b f < b f<b
  • 1 ≤ c , e ≤ 4 × 1 0 12 1\leq c, e \leq4×10^{12} 1c,e4×1012

If there are multiple solutions, you can print anyone.

If there are no solution, please print “-1 -1 -1 -1” in this line.

输入描述
The first line contains one integer t t t ( 1 ≤ t ≤ 1 0 5 ) (1\leq t\leq 10^5) (1t105) — the number of test cases.

The only line of each test case contains two integers a a a and b b b ( a , b ≤ 2 × 1 0 6 ) (a, b\leq2×10^6) (a,b2×106)

输出描述

For each test case print four integers — c , d , e , f c,d,e,f c,d,e,f. If there are no solution, c , d , e , f c,d,e,f c,d,e,f should all be − 1 -1 1.

输入
3 3 3
4 4 4 1 1 1
1 1 1 6 6 6
37 37 37 111 111 111

输出
− 1 -1 1 − 1 -1 1 − 1 -1 1 − 1 -1 1
1 1 1 2 2 2 1 1 1 2 2 2
145 145 145 87 87 87 104 104 104 78 78 78

思路

  • 情况一: b = = 1 b == 1 b==1 b b b是质数 无解
  • 情况二: g c d ( a , b ) ! = 1 gcd(a,b)!=1 gcd(a,b)!=1
    假设 k = g c d ( a , b ) k=gcd(a,b) k=gcd(a,b)则存在一组解 ( a / k + 1 , b / k , 1 , b / k ) (a/k + 1, b/k, 1, b/k) (a/k+1,b/k,1,b/k)
  • 情况三:b不是质数
    即b可以分成两个相异质因数相乘,所以先找到 d 、 f d、f df使得 d × f = b d×f=b d×f=b d 、 f d、f df互质
    找d,f的方法:先打表3e6以内的素数,然后先找出第一个被b整除的素数,这个数就是d,然后f就是b/d(类似算数基本定理)

在d,f找到之后就开始找c和e了。

已知d*f = b,通分后可得 c × f − e × d = a c×f-e×d=a c×fe×d=a(d、f、a都知道,求c、e),求解c和e,即用扩展欧几里得算法。

注意:求出c和e之后判断一下谁正谁负,毕竟d和f和b的两个相异质因数是不知道对应谁的,可以通过c和e的正负性判断。

Code

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef pair<int, int> pdd;

#define INF 0x7f7f7f
#define mem(a,b) memset(a , b , sizeof(a))
#define FOR(i, x, n) for(int i = x;i <= n; i++)
// const ll mod = 1e9 + 7;
 const int maxn = 5e6 + 10;
// const double eps = 1e-6;


int prime[1005]; // 素数数组
bool is_prime[maxn]; // is_prime[i]表示i为素数
int p;

void sieve() // 返回n以内的素数个数
{
    int n = maxn;
    mem(is_prime, true);
    is_prime[0] = is_prime[1] = false;
    is_prime[2] = true;
    
    for(int i = 2;i * i <= n; i++)
    {
        if(is_prime[i])
        {
            prime[++p] = i;
            for(int j = 2 * i;j <= n; j += i)
            {
                is_prime[j] = false;
            }
        }
    }
}

ll gcd(ll a, ll b)
{
    return b == 0 ? a : gcd(b, a % b);
}

ll ex_gcd(ll a, ll b, ll &x, ll &y)
{
    ll res, t;
    if(!b)
    {
        x = 1;
        y = 0;
        return a;
    }
    res = ex_gcd(b, a % b, x, y);
    t = x;
    x = y;
    y = t - (a / b) * y;
    return res;
}

ll solve_ex_gcd(ll a, ll b, ll c, ll &x, ll &y)
{
    ll inv = ex_gcd(a, b, x, y);
    if(c % inv)
    {
        x = -1;
        y = -1;
        return -1;
    }
    x *= (c / inv);
    y *= (c / inv);
    return 0;
}

void solve()
{
    ll a, b;
    cin >> a >> b;
    ll k = gcd(a, b);
    if(k != 1)
    {
        a /= k;
        b /= k;
        cout << a + 1 << " " << b << " " << 1 << " " << b << endl;
        return ;
    }
    if(b == 1 || is_prime[b])
        cout << "-1 -1 -1 -1" << endl;
    else
    {
        ll tmp = 0, time = 0;
        ll bb = b;
        for(int i = 1;i <= p && bb != 1; i++) // 找两个素因数
        {
            if(bb % prime[i] == 0)
            {
                tmp = prime[i];
                while(bb % prime[i] == 0)
                {
                    time++;
                    bb /= prime[i];
                }
                break;
            }
        }
        if(bb == 1)
        {
            cout << "-1 -1 -1 -1" << endl;
            return ;
        }
        ll d = 1;
        for(int i = 1;i <= time; i++)
        {
            d *= tmp; // b的一个因数
        }
        ll f = bb; // b的另一个因数
        ll c = 0, e = 0;
        solve_ex_gcd(f, d, a, c, e);
        if(c < 0 && e > 0)
        {
            cout << e << " " << f << " " << -c << " " << d << endl;
        }
        else
            cout << c << " " << d << " " << -e << " " << f << endl;
    }
}

signed main()
{
    ios_base::sync_with_stdio(false);
    //cin.tie(nullptr);
    //cout.tie(nullptr);
#ifdef FZT_ACM_LOCAL
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#else
    ios::sync_with_stdio(false);
    sieve();
    int T = 1;
    cin >> T;
    while(T--)
        solve();
#endif
    return 0;
}

你可能感兴趣的:(数论,题解)