2020牛客暑期多校第三场F-Fraction Construction Problem-分数构造题(拓展欧几里得)

题目大意:给你一个$a$,$b$表示$frac{a}{b}$,问你能否构造一个$frac{c}{d}-frac{e}{f}=frac{a}{b}$,如果能请输出c,d,e,f。否则输出-1 -1 -1 -1.要求$b>d,b>f,1<=c,e<=4e14$。

emmm,有三种情况:

第一种是分子分母不是最简,那么也就是说a,b存在一个公因子,同时也说明了b不是一个质数。那么我们可以直接构造$frac{a}{b}=frac{a+x}{b}-frac{x}{b}$,然后我们对分子分母同除以a,b的一个公因子,我们设为g,那么就会有$frac{a}{b}=frac{frac{a+x}{g}}{frac{b}{g}}-frac{frac{x}{g}}{frac{b}{g}}$,那么由于x是可以任意取的,那么我们为了方便,可以直接将其设为g,那么会得到$frac{a}{b}=frac{frac{a}{g}+1}{frac{b}{g}}-frac{1}{frac{b}{g}}$

第二种情况,分子分母最简了,但分母的不相同的质因子不超过一个,那么无解。如果分母不相同的质因子不超过一个,那么也就是说$b$可以表示为$p^k$,那么$frac{c}{d}-frac{e}{f}=frac{a}{p^k}$,最后化简的时候一定有$d'=p^{k_1},f'=p^{k_2}$,那么$d,f$一定包含因子$p^{s}$那么对于$cf,de$也一定包含因子$p^{ss}$,也就是说他们一定有公因子$p^m$。这就和分子分母最简相互矛盾了

第三种情况,分子分母最简了,但分母的不相同的质因子超过一个。那么一定有$df=b,gcd(d,f)=1$。那么我们只需要找到符合条件的$d,f$,然后带入到上面的式子就是$cf-ed=a$,那么可以看成$fx-dy=gcd(f,d)*a$。。。。这似乎就是拓展欧几里得了解决的问题了,拓展欧几里得不过关的话我也挺绝望的QAQ。。。

以下是AC代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int mac=2e6+10;

int min_prim[mac],prim_num[mac];
int vis[mac];

void init()
{
    int m=sqrt(mac);
    for (int i=2; i<m; i++){
        if (!vis[i]){
            min_prim[i]=i;
            for (int j=i*i; j<mac; j+=i){
                vis[j]=1;
                if (!min_prim[j]) min_prim[j]=i;//找到每个数的最小质因子
            }
        }
    }
    for (int i=1; i<mac; i++){
        if (!vis[i]) continue;
        prim_num[i]++;
        int x=i;
        while (x%min_prim[i]==0) x/=min_prim[i];
        if (x!=1) prim_num[i]++;//判断是否有两个互异的质因子 
    }
}

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

int main(int argc, char const *argv[])
{
    int t;
    init();
    scanf ("%d",&t);
    while (t--){
        int a,b;
        scanf ("%d%d",&a,&b);
        int g=__gcd(a,b);
        if (g!=1) {
            printf("%d %d %d %d
",a/g+1,b/g,1,b/g);
            continue;
        }
        if (prim_num[b]<=1) {printf("-1 -1 -1 -1
"); continue;}
        ll d=1,f=b;
        while (f%min_prim[b]==0) {
            f/=min_prim[b];
            d*=min_prim[b];
        }
        ll c,e;
        exgcd(f,d,c,e);
        e=-e;
        while (e<0 || c<0) e+=f,c+=d;
        printf ("%lld %lld %lld %lld
",1LL*c*a,d,1LL*e*a,f);
    }
    return 0;
}
路漫漫兮
原文地址:https://www.cnblogs.com/lonely-wind-/p/13339092.html