2019HDU多校第五场A fraction —— 辗转相除法|类欧几里得
题目
设 $ab^{-1} = x(mod \ p)$,给出 $x,p$,要求最小的 $b$,其中 $0< a < b, \ 1 < x<p,\ 3 \leq x\leq {10}^{15}$.
分析
比赛中,首先就想用扩展欧几里得解出一个可行 $b$,然后枚举 $kb \% p$ 的最小值,然后发现复杂度爆炸。
看题解,用了一种非常巧妙地方法,
$\because 0 < a=bx-pt < b$
$\therefore \frac{p}{x} < \frac{b}{t} < \frac{p}{x-1}$
按题解,这是一个经典问题,可以用辗转相除法解决。
如,对于 $\frac{a}{b} < \frac{x}{y} < \frac{c}{d}$
若 $\left \lfloor \frac{a}{b} \right \rfloor \neq \left \lfloor \frac{c}{d} \right \rfloor$,直接取 $x = \left \lfloor \frac{a}{b} \right \rfloor, y = 1$;
若 $\left \lfloor \frac{a}{b} \right \rfloor = \left \lfloor \frac{c}{d} \right \rfloor$,先统一减去整数部分,然后取倒数,即 $\frac{d}{c} < \frac{y}{x} < \frac{b}{a}$.
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll p, x; //q求满足a/b < x/y < c/d 的最小的x和y void f(ll a, ll b, ll c, ll d, ll& x, ll& y) { ll tmp = (a+b-1)/b; if(tmp <= c/d) { x=tmp; y=1; return; } a -= b*(tmp-1); //x -= y*tmp; c -= d*(tmp-1); f(d, c, b, a, y, x); x += y*(tmp-1); } int main() { int T; scanf("%d", &T); while(T--) { scanf("%lld%lld", &p, &x); ll b, t; f(p, x, p, x-1, b, t); ll a = b*x-p*t; printf("%lld/%lld\n", a, b); } return 0; }
续:后来知道这种方法叫类欧几里得算法,与欧几里得相似,采用辗转相除的方法。
个性签名:时间会解决一切