1. 程式人生 > 實用技巧 >2020牛客暑期多校第三場F-Fraction Construction Problem-分數構造題(拓展歐幾里得)

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\n",a/g+1,b/g,1,b/g); continue; } if (prim_num[b]<=1) {printf("-1 -1 -1 -1\n"); 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\n",1LL*c*a,d,1LL*e*a,f); } return 0; }