牛客多校第三场 F. Fraction Construction Problem(扩展欧几里得,质因数分解)

牛客多校第三场 F. Fraction Construction Problem(扩展欧几里得,质因数分解)_第1张图片

总感觉这题在去年湖南多校里见过

题意:
题目给了你一个等式,给出你a,b,问是否有满足条件的c,d,e,f

思路:
其实感觉这种题,一定和约数有关,不然你枚举不了。
正解是对b质因数分解,分出两个互质的数,分别赋个d和f,那么可以得到等式 d ∗ e − c ∗ f = a d*e-c*f=a decf=a,这对应了扩展欧几里得方程,且两个系数互质,这保证了一定有解。解出一组合理解即可。

如果b和a不互质的话,可以直接分解输出。

如果 b b b a a a互质,且 b b b没有大于2个的素因子,那么无解。

证明为:将 b b b分解为 p k p^k pk b b b a a a互质,则左边的数通分约分后一定分别等于 a , b a,b a,b。但是左边的分子对素数 p p p的指数都小于 k k k,所以通分约分后不可能得出包含 p k p^k pk因子的分子,所以无解。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

typedef long long ll;

typedef long long ll;
const int maxn = 2e6 + 7;

vector<ll>Div;

ll gcd(ll n,ll m) {
    return m == 0 ? n : gcd(m,n % m);
}

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

int prime[maxn],b[maxn],v[maxn],cnt;

void getprime() {
    for(int i = 2;i < maxn;i++) {
        if(v[i] == 0) {
            v[i] = i;prime[++cnt] = i;
        }
        for(int j = 1;j <= cnt && i * prime[j] < maxn;j++) {
            v[i * prime[j]] = prime[j];
            if(i % prime[j] == 0)break;
        }
    }
}

int main() {
    getprime();
    int T;scanf("%d",&T);
    while(T--) {
        ll a,b;scanf("%lld%lld",&a,&b);
        ll Gcd = gcd(a,b);
        if(Gcd != 1) {
            printf("%lld %lld %lld %lld\n",a * 2 / Gcd,b / Gcd,a / Gcd,b / Gcd);
            continue;
        }
        
        if(v[b] == b || b == 1) {
            printf("-1 -1 -1 -1\n");
            continue;
        }
        
        ll c = -1,d = -1,e = -1,f = -1;
        for(int i = 1;i <= cnt && prime[i] <= b;i++) {
            ll num = 1,tmp = b;
            while(tmp % prime[i] == 0) {
                tmp /= prime[i];
                num *= prime[i];
                f = num;
            }
            if(num != 1) {
                f = num;d = b / num;
                break;
            }
        }
        
        if(f == b) {
            printf("-1 -1 -1 -1\n");
            continue;
        }
        
        ll D = exgcd(f,d,c,e);
        c = a / D * c;
        e = a / D * e;
        
        ll mod1 = d / D,mod2 = f / D;
        ll k1 = 0,k2 = 0;
        if(c <= 0) {
            k1 = max(k1,-c / mod1 + 1);
        }
        if(e >= 0) {
            k2 = max(k2,e / mod2 + 1);
        }
        c += max(k1,k2) * mod1;
        e -= max(k1,k2) * mod2;
        
        
        printf("%lld %lld %lld %lld\n",c,d,-e,f);
    }
    return 0;
}

你可能感兴趣的:(#,其他比赛题目,#,扩展欧几里得,#,素数)