牛客多校3 - Fraction Construction Problem(扩展欧几里得)

题目链接:点击查看

题目大意:给出 a 和 b ,求解满足条件的 c,d,e,f ,使得:

  1. \frac{c}{d}-\frac{e}{f}=\frac{a}{b}
  2. d < b
  3. f < b
  4. c,e 均为小于等于 4e12 的正整数

题目分析:分情况讨论一下,首先如果 a 和 b 可以约分的话,那么直接约分后,输出 a+1 , b , 1 , b 显然就是答案了,如果不能约分的话,且 b 的相异质因子的个数不超过 1 个的话,那么是无解的,证明如下:(来自官方题解)

牛客多校3 - Fraction Construction Problem(扩展欧几里得)_第1张图片

最后一种情况就是 b 的相异质因子个数超过一个,对于这种情况可以将条件 1 的公式转换一下: \frac{c}{d}-\frac{e}{f}=\frac{a}{b}=\frac{cf-de}{df}

这样一来,d 和 f 显然就是 b 的两个相异质因子了,而 cf - de = a ,在已知 d 和 f 的前提下,一定有解,且可以用扩展欧几里得来解决,注意最后求出来的答案需要处理一下,因为需要保证 c 和 e 为正整数

在找 d 和 f 的时候也有技巧,如果 sqrt( n ) 暴力去找的话,会超时,所以可以用埃氏筛预处理一下,保存一下每个数字的最大质因子,这样就可以令 d 为该质因子的幂,然后 f = b / d 了

代码:
 

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
 
typedef long long LL;
 
typedef unsigned long long ull;
 
const int inf=0x3f3f3f3f;
 
const int N=2e6+100;

int pri[N];//pri[i]:i的最大质因子为pri[i]
 
template void exgcd(T a,T b,T &d,T &x,T &y){
    if(!b) {d=a;x=1;y=0;}
    else {exgcd(b,a%b,d,y,x);y-=x*(a/b);}
}
//求解二元一次方程 a*x+b*y=c,一组解为x,y,无解则返回false
template bool Solve_equation(T a,T b,T c,T &x,T& y){
    T gcd;
    exgcd(a,b,gcd,x,y);
    if(c%gcd) return false;   //无解
    T k=c/gcd;
    x*=k;y*=k;
    T xplus=b/gcd,yplus=a/gcd; 
    if(xplus<0) xplus*=-1;if(yplus<0) yplus*=-1;
    //此时求出的x,y即为一组解,该方程的通解形式为X=x+t*(b/gcd),Y=y-t*(a/gcd) t为任意正整数
    //根据题目要求我们需要构造特殊解
    //x=(x%xplus+xplus)%xplus;y=c-a*x; //x的最小正整数解
    //y=(y%yplus+yplus)%yplus;x=c-b*y; //y的最小正整数解
    return true;
}

void init()
{
    pri[1]=1;
    for(int i=2;i>w;
    while(w--)
    {
        LL a,b;
        scanf("%lld%lld",&a,&b);
        LL gcd=__gcd(a,b);
        a/=gcd,b/=gcd;
        if(gcd!=1)
        {
            printf("%lld %lld %lld %lld\n",a+1,b,1,b);
            continue;
        }
        LL d=1,f=b;
        while(pri[b]!=1&&f%pri[b]==0)
        {
            f/=pri[b];
            d*=pri[b];
        }
        if(f==1)//只有一个质因子 
        {
            printf("-1 -1 -1 -1\n");
            continue;
        }
        LL c,e;
        Solve_equation(f,-d,a,c,e);
        LL k=abs(min(c/d,e/f))+1;
        c+=d*k,e+=f*k;
        printf("%lld %lld %lld %lld\n",c,d,e,f);
    }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
    return 0;
}

 

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