题目
设 $ab^{-1} = x(mod p)$,给出 $x,p$,要求最小的 $b$,其中 $0< a < b, 1 < x<p, 3 leq xleq {10}^{15}$.
分析
比赛中,首先就想用扩展欧几里得解出一个可行 $b$,然后枚举 $kb \% p$ 的最小值,然后发现复杂度爆炸。
看题解,用了一种非常巧妙地方法,
$ecause 0 < a=bx-pt < b$
$ herefore frac{p}{x} < frac{b}{t} < frac{p}{x-1}$
按题解,这是一个经典问题,可以用辗转相除法解决。
如,对于 $frac{a}{b} < frac{x}{y} < frac{c}{d}$
若 $left lfloor frac{a}{b} ight floor eq left lfloor frac{c}{d} ight floor$,直接取 $x = left lfloor frac{a}{b} ight floor, y = 1$;
若 $left lfloor frac{a}{b} ight floor = left lfloor frac{c}{d} ight floor$,先统一减去整数部分,然后取倒数,即 $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 ", a, b); } return 0; }
续:后来知道这种方法叫类欧几里得算法,与欧几里得相似,采用辗转相除的方法。