HDU6624 fraction
题意:求满足a < b and a ≡ bx (mod p)成立的最小b,并以分数形式输出a / b。
p是质数,3 <= p <= 1e15, 1 < x <p, 1 <= T <= 2e5次查询
思路:由同余的定义考虑将等式转换一下 ,转换成 a = bx - py。
再由题目限制条件可以得到 0 < a = bx - py < b.
由 0 < bx - py 可以得到 p / x < b / y;
由 bx - py < b 可以得到 b /y < p / (x - 1)
所以可以得到 p / x < b / y < p / (x - 1).
然后转换成求 b / a < x / y < d / c.成立的最小x.
dalao们都说这是一个经典问题orz 萌新瑟瑟发抖
大致理解了一下大佬们的想法,辗转相除,和扩展欧几里得比较相似。
算法流程:
假设 p1 = b / a, p2 = d / c.
-
如果p1 != p2, 也就是两个分式整数部分不相同,那么x = p1 + 1, y = 1就是成立的最小分式
这个显然 -
p1 == p2. 分式通分一下 (b - a * p1) / a < (x - y * p1) / y < ( d - c * p1) / c
那么上述不等式中通分相减之后分子都小于分母了。我们的目的是最小化x
考虑分子分母翻转一下:a / (b - a * p1) > y / (x - y * p1) > c / ( d - c * p1)
此时不妨令b’ = c, a ’ = ( d - c * p1), x ’ = y, y’ = (x - y * p1), d ’ = b, c ’ = (b - a * p1)
我们又将问题转换成以一个求解 b’ / a’ < x ’ / y’ < d’ / c’ 成立的最小的x’的子问题,转会步骤1,2递归进行 -
于是我们可以将这个新的不等式递归的求解直到p1 != p2。
AC code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
void ex(ll b, ll a, ll d, ll c, ll &x, ll &y){
ll p1 = b / a, p2 = d / c;
if(p1 != p2){
y = 1, x = p1 + 1;
return ;
}
b -= a * p1;
d -= c * p2;
ex(c, d, a, b, y, x); //分子分母翻转
x += y * p1; //递归求解
}
int main(){
ll p, a;
int T;
scanf("%d", &T);
while(T--){
scanf("%lld%lld", &p, &a);
ll x, y;
ex(p, a, p, a - 1, x, y);
ll ans = x * a - p * y;
printf("%lld/%lld\n", ans, x);
}
return 0;
}