Fraction Construction Problem 2020牛客多校第三场(扩展欧几里得)

原题题面

有T个输入。
每组输入给出两个正整数 a , b ( a , b 2 × 1 0 6 ) a,b(a,b\leq 2 × 10^6)
请找到四个正整数 c , d , e , f ( f < b , d < b , 1 c , e 4 × 1 0 12 ) c,d,e,f(f<b,d<b,1\leq c,e \leq 4× 10^{12}) ,使他们满足:
c d e f = a b \frac{c}{d}-\frac{e}{f}=\frac{a}{b}
如果有多组数据,输出其中一组。如果不存在,输出“-1 -1 -1 -1”。

输入样例

3
4 1
1 6
37 111

输出样例

-1 -1 -1 -1
1 2 1 3
145 87 104 78

题面分析

首先显然,当 g c d ( a , b ) gcd(a,b) 不为1时,我们可以令 a = a g c d ( a , b ) , b = b g c d ( a , b ) a'=\frac{a}{gcd(a,b)},b'=\frac{b}{gcd(a,b)} 。构造
a + 1 b 1 b = a b \frac{a'+1}{b'}-\frac{1}{b'}=\frac{a}{b}
所以输出"a’+1 b’ 1 b’"即可。
g c d ( a , b ) = 1 gcd(a,b)=1 时,易知
c d e f = c f d e d f \frac{c}{d}-\frac{e}{f}=\frac{cf-de}{df}
d f = k b df=kb (k为正整数)
首先我们可以证明一下结论:
结论①: b b 不能是质数或1。
证明:
b不能是1显然。
假设 b b 是质数,那 b b 的因子只有 1 , b 1,b ,即 d , f d,f 只能分别取1和b的倍数,这与 d < b , f < b d<b,f<b 矛盾。故①得证。
结论②: b b 不能是质数幂(即 p k p^k )
证明:
假设 b = p k b=p^k ,设 d = p a d=p^a ,则 f = p k a f=p^{k-a} ,由扩展欧几里得得知 c f d e = a cf-de=a 有正整数解的充要条件是 g c d ( d , f ) a gcd(d,f)|a g c d ( d , f ) = p m i n { a , k a } gcd(d,f)=p^{min\{a,k-a\}} 。但因为 g c d ( a , b ) = 1 gcd(a,b)=1 ,故 a a 的质因子里没有 p p ,即 g c d ( d , f ) a gcd(d,f)\nmid a ,矛盾。故②得证。
由结论①②可知结论③: b b 的质因子至少拥有两个
根据③,我们设 b = i = 1 m p i k i b=\sum_{i=1}^{m}p_{i}^{k_i} ,令 d = p 1 k 1 , f = b / d , d=p_{1}^{k_1},f=b/d, 易知 g c d ( d , f ) = 1 gcd(d,f)=1
c f d e = a cf-de=a 必有解,可以用扩展欧几里得求出 c , e c,e
需要注意的是,如果最后 c < 0 , e > 0 c<0,e>0 ,其实不需要对扩展欧几里得的解做一些操作,只需要调换 c / d , e / f c/d,e/f 的位置即可。

AC代码(123ms)

#include <bits/stdc++.h>
using namespace std;
const int MAXN=5e6;
int prime[1000];//素数数组
bool is_prime[MAXN+10];//is_pri[i]表示i是否是素数
int sieve()//埃式筛
{
    int n=MAXN;
    int p=0;
    for(int i=0; i<=n; i++)
        is_prime[i]=true;
    is_prime[0]=is_prime[1]=false;
    is_prime[2]=true;

    for(int i=2; i<=sqrt(n); i++)
    {
        if (is_prime[i])
        {
            prime[++p]=i;
            for(int j=2*i; j<=n; j+=i)
                is_prime[j]=false;
        }
    }
    return p;
}
long long extended_gcd(long long a, long long b, long long &x, long long &y)
//扩展gcd
{
    long long r, t;
    if (b==0)
    {
        x=1;
        y=0;
        return a;
    }
    r=extended_gcd(b, a%b, x, y);
    t=x;
    x=y;
    y=t-(a/b)*y;
    return r;
}
long long solve_exgcd(long long a, long long b, long long c, long long &x, long long &y)
{
    long long p=extended_gcd(a, b, x, y);
    if (c%p)
    {
        x=-1;
        y=-1;
        return -1;
    }
    x*=(c/p);
    y*=(c/p);
    return 0;
}
void solve1()
{
    long long pp=sieve();
    int t;
    scanf("%d", &t);
    while(t--)
    {
        long long a, b;
        scanf("%lld%lld", &a, &b);
        if (__gcd(a, b)!=1)// ka/kb
        {
            long long v=__gcd(a, b);
            a/=v;
            b/=v;
            printf("%lld %lld %lld %lld\n", a+1, b, 1, b);
            continue;
        }
        else
        {
            if (b==1 || is_prime[b])//特判无解情况1
            {
                printf("-1 -1 -1 -1\n");
                continue;
            }
            long long sum=0;
            long long tmp,time=0;
            long long bb=b;
            for(int i=1;i<=pp && bb!=1;i++)
            {
                if(bb%prime[i]==0)
                {
                    tmp=prime[i];
                    while(bb%prime[i]==0)
                    {
                        bb/=prime[i];
                        time++;
                    }
                    break;
                }
            }
            if(bb==1)//特判情况2
            {
                printf("-1 -1 -1 -1\n");
                continue;
            }
            long long d=1;
            for(int i=1; i<=time; i++)
            {
                d*=tmp;
            }
//            printf("d=%lld\n",d);
            long long f=bb;
            long long c=0, e=0;
            solve_exgcd(f, d, a, c, e);
            if (c<0 && e>0)
                printf("%lld %lld %lld %lld\n", e, f, -c, d);//两个调过来
            else
                printf("%lld %lld %lld %lld\n", c, d, -e, f);
        }
    }
}
int main()
{
//    ios_base::sync_with_stdio(false);
//    cin.tie(0);
//    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
    long long test_index_for_debug=1;
    char acm_local_for_debug;
    while(cin>>acm_local_for_debug)
    {
        cin.putback(acm_local_for_debug);
        if (test_index_for_debug>100)
        {
            throw runtime_error("Check the stdin!!!");
        }
        auto start_clock_for_debug=clock();
        solve1();
        auto end_clock_for_debug=clock();
        cout<<"\nTest "<<test_index_for_debug<<" successful"<<endl;
        cerr<<"Test "<<test_index_for_debug++<<" Run Time: "
            <<double(end_clock_for_debug-start_clock_for_debug)/CLOCKS_PER_SEC<<"s"<<endl;
        cout<<"--------------------------------------------------"<<endl;
    }
#else
    solve1();
#endif
    return 0;
}

后记

赛时差一点就对了…
感谢赛后蔡队的指点 (CSLNB!)
DrGilbert 2020.7.18

猜你喜欢

转载自blog.csdn.net/oampamp1/article/details/107433921