题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6624
题目大意:给定
p
,
x
p,x
p,x,存在两整数
a
,
b
a,b
a,b,求解满足
a
<
b
,
a
≡
b
x
(
m
o
d
p
)
a<b,\ a≡bx(mod \ p)
a<b, a≡bx(mod p)的最小值
b
b
b。
思路:
令
a
=
b
x
−
c
p
a=bx-cp
a=bx−cp,则存在不等式
0
≤
b
x
−
c
p
≤
b
0\le{bx-cp}\le{b}
0≤bx−cp≤b,
变换一下得到:
p
x
<
b
c
<
p
x
−
1
\frac{p}{x}\lt{\frac{b}{c}\lt{\frac{p}{x-1}}}
xp<cb<x−1p,我们要解出这个不等式中的
m
i
n
(
b
)
min(b)
min(b)值。
这时候可以想到运用类似于辗转相除法的形式来解决这个问题:
(1)令
z
1
=
⌊
p
x
⌋
,
z
2
=
⌊
p
x
−
1
⌋
z_1=\lfloor\frac{p}{x}\rfloor,\ z_2=\lfloor\frac{p}{x-1}\rfloor
z1=⌊xp⌋, z2=⌊x−1p⌋,
(2)如果
z
1
!
=
z
2
z_1!=z_2
z1!=z2,则令
c
=
1
,
b
=
z
1
+
1
c=1,b=z_1+1
c=1,b=z1+1(因为不含等号,所以要加1)跳出循环。否则就执行(3)。
(3)不等式同步减掉
z
1
z_1
z1,不等式变为:
p
−
z
1
∗
x
x
<
b
−
z
1
∗
c
c
<
p
−
z
1
∗
(
x
−
1
)
x
−
1
\frac{p-z_1*x}{x}\lt{\frac{b-z_1*c}{c}\lt{\frac{p-z_1*(x-1)}{x-1}}}
xp−z1∗x<cb−z1∗c<x−1p−z1∗(x−1),分子分母翻转一下得到:
x
−
1
p
−
z
1
∗
(
x
−
1
)
<
c
b
−
z
1
∗
c
<
x
p
−
z
1
∗
x
\frac{x-1}{p-z_1*(x-1)}\lt{\frac{c}{b-z_1*c}\lt{\frac{x}{p-z_1*x}}}
p−z1∗(x−1)x−1<b−z1∗cc<p−z1∗xx,这个式子和最初得到的原式
(
p
x
<
b
c
<
p
x
−
1
)
(\frac{p}{x}\lt{\frac{b}{c}\lt{\frac{p}{x-1}}})
(xp<cb<x−1p)是不是有点相像,两式对应一下递归就
o
k
ok
ok了。
证明:算法正确性菜鸡无法证明,很像辗转相除法。
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll p,xx;
ll b,c;
void solve(ll p,ll x,ll &b,ll &c,ll pp,ll y)//y=x-1
{
ll z1=p/x;
ll z2=pp/y;
if(z1!=z2){
c=1;
b=z1+1;//因为不等式不带等号
return ;
}
p-=z1*x;
pp-=z1*y;
b-=c*z1;
solve(y,pp,c,b,x,p);
b+=c*z1;
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
scanf("%lld%lld",&p,&xx);
b=0;
c=0;
solve(p,xx,b,c,p,xx-1);//按照不等式从左到右依次传参
ll a=b*xx-c*p;
printf("%lld/%lld\n",a,b);
}
return 0;
}
/*
3
11 7
998244353 554580197
998244353 998244352
2/5
8/9
499122176/499122177
*/