2020牛客暑期多校训练营Fraction Construction Problem(扩展欧几里得)

Fraction Construction Problem

题目描述

2020牛客暑期多校训练营Fraction Construction Problem(扩展欧几里得)_第1张图片

输入描述:

2020牛客暑期多校训练营Fraction Construction Problem(扩展欧几里得)_第2张图片

输出描述:

在这里插入图片描述

示例1

输入

3
4 1
1 6
37 111

输出

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

题目大意

对于整式在这里插入图片描述
给定a,b的值,求任意一组c,d,e,f的值使得等式成立。
无解则输出-1-1-1-1。

分析

2020牛客暑期多校训练营Fraction Construction Problem(扩展欧几里得)_第3张图片
首先看这个式子,在d*f==b时可以化成这样,一拍脑瓜想到可以用扩欧解方程。

所以我们只要把b分解成d*f,并且满足gcd(d,f)=1,这样就可以使构造成立(通分的知识,学前班的),然后一套模板解方程。于是我们凑出了一组答案。

有的童鞋想,那那那我d和f其中一个为1不就可以了。
嗯没错,可是题目中说了,d和f均小于b(不然不是水题了?),所以我们需要找出b的两个互质因子。
但是如果a和b不是互质的,那就一约分后d或f就可以取1了。所以这种情况可以直接特判掉,即方便又省时(非常的nice)。

无解

但是也有可能他找不到一对互质因子,那就是无解了。比如b=81,它不能分解成互质因子。除此以外,b=1或b是质数当然也是无解的情况。
(无解判断方式有很多,自行选择)

综述

1、gcd(a,b)!=1,直接使d(或f)=0,出答案,简洁明了。
2、gcd(a,b)=1&&(prime(b)||b无法拆成互质数之积||b=1),则无解,畅快淋漓,速战速决。
3、其他有解情况,则用扩欧解方程,然后通过解的正负判断对应。

代码

#include
#define ll long long
using namespace std;
const int MAXN=2e6+10;
int gcd(int a,int b){return a%b==0?b:gcd(b,a%b);}//听+说ll会TLE,果然。
ll exgcd(ll a,ll b,ll &x,ll &y){
    if(b==0){x=1;y=0;return a;}
    ll c=exgcd(b,a%b,y,x);
    y-=a/b*x;return c;
}//扩欧
int main()
{
    int t,a,b,r;
    for(scanf("%d",&t);t--;){//学习dalao的新操作
        scanf("%d%d",&a,&b);
        if(b==1){puts("-1 -1 -1 -1");continue;}//b是1不要再继续了,省时。
        r=gcd(a,b);
        if(r!=1){
            printf("%d %d %d %d\n",a/r+b/r,b/r,b/r,b/r);
            continue;
        }//ab不互质直接出答案
        ll x,y;
        int d=1,f=b;
        for(d=2;d*d<=b;d++)
            if(b%d==0&&gcd(d,b/d)==1){
                d*=1ll,f=1ll*b/d;break;
            }//穷举法求素因子,也可以用类筛法。
        if(f==b){puts("-1 -1 -1 -1");continue;}//找不到合法的分解,素数也包含在内。
        r=exgcd(f,d,x,y);//解方程
        x=x*1ll*a;y=y*1ll*a;//扩欧基本操作--求通解
        if(x>0&&y<0)
            printf("%lld %d %lld %d\n",x,d,-y,f);
        else
            printf("%lld %d %lld %d\n",y,f,-x,d);
        //根据正负判断对应
    }
}

END

有错即评。

你可能感兴趣的:(2020牛客多校)