题目大意
给定两个数
a
,
m
a,m
a,m ,求满足
a
u
≡
u
(
m
o
d
m
)
a^u \equiv u (mod\ \ m)
au≡u(mod m) 的一个解。
(
1
≤
a
,
m
≤
1
0
9
,
0
≤
u
≤
1
0
18
)
(1\leq a,m \leq10^9 ,0\leq u\leq 10^{18})
(1≤a,m≤109,0≤u≤1018)
题解
参考了讨论区 https://blog.nowcoder.net/n/576f9463036346f0a0fb04fee50fac75 的方法
求解
考虑使用欧拉定理,考虑
b
>
=
ϕ
p
b>=\phi_p
b>=ϕp的情况。
a
u
≡
{
a
u
%
ϕ
m
g
c
d
(
a
,
u
)
=
1
a
u
%
ϕ
i
+
ϕ
m
g
c
d
(
a
,
u
)
!
=
1
(
m
o
d
m
)
a^u\equiv\begin{cases}a^{u\% \phi_m }&gcd(a,u)=1\\a^{u\% \phi_i+\phi_m}& gcd(a,u)!=1\end{cases}(mod \ m)
au≡{au%ϕmau%ϕi+ϕmgcd(a,u)=1gcd(a,u)!=1(mod m)
定义
d
=
u
%
ϕ
m
d=u\%\phi_m
d=u%ϕm 或
u
%
ϕ
m
+
ϕ
m
u\%\phi_m+\phi_m
u%ϕm+ϕm 和
k
∗
ϕ
p
+
d
=
u
(
k
>
=
0
)
k*\phi_p+d=u(k>=0)
k∗ϕp+d=u(k>=0)
则原式可以转化为
a
d
≡
d
+
k
∗
ϕ
m
(
m
o
d
m
)
a^d \equiv d+k*\phi_m (mod\ m)
ad≡d+k∗ϕm(mod m)
移项可以得到
a
d
−
d
≡
k
∗
ϕ
m
(
m
o
d
m
)
a^d-d\equiv k*\phi_m(mod\ m)
ad−d≡k∗ϕm(mod m)
ϕ
m
∗
x
1
+
m
∗
y
1
≡
g
c
d
(
ϕ
m
,
m
)
(
m
o
d
m
)
\phi_m*x1+m*y1\equiv gcd(\phi_m,m) (mod \ m)
ϕm∗x1+m∗y1≡gcd(ϕm,m)(mod m) 是一个已知有解的同余方程
回到上一个方程想要得到解
k
k
k ,显然要满足
a
d
−
d
=
x
∗
g
c
d
(
m
,
ϕ
m
)
,
(
x
>
0
)
a^d-d=x *gcd(m,\phi_m),(x>0)
ad−d=x∗gcd(m,ϕm),(x>0)
也就是
a
d
≡
d
(
m
o
d
g
c
d
(
m
,
ϕ
m
)
)
a^d \equiv d (mod \ gcd(m,\phi_m))
ad≡d(mod gcd(m,ϕm))。
重新得到了题目,但是模数缩小了,因此我们想到了递归,直到模数为
1
1
1 时直接推出答案。
回溯
假设我们已经得到了最后一组解
d
=
0
d=0
d=0 ,
求解同余方程
a
d
−
d
≡
k
∗
ϕ
m
(
m
o
d
m
)
a^d-d\equiv k*\phi_m(mod\ m)
ad−d≡k∗ϕm(mod m),使用扩展欧几里得定理,推出
x
1
x1
x1 的值,
k
=
x
1
∗
a
d
−
d
g
c
d
(
m
,
ϕ
m
)
%
m
o
d
k=x1*\frac{a^d-d}{gcd(m,\phi_m)}\%mod
k=x1∗gcd(m,ϕm)ad−d%mod
由于
a
d
a^d
ad 超出范围,根据
a
b
%
(
b
∗
c
)
=
a
%
(
b
∗
c
)
b
\frac{a}{b}\%(b*c)=\frac{a\%(b*c)}{b}
ba%(b∗c)=ba%(b∗c)得出
k
=
x
1
∗
(
a
d
−
d
)
%
m
/
ϕ
m
k=x1*(a^d-d)\%m/\phi_m
k=x1∗(ad−d)%m/ϕm 。
再利用
k
∗
ϕ
p
+
d
=
u
k*\phi_p+d=u
k∗ϕp+d=u,得出结果即可。
参考代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll phi(ll x)
{
ll ans=x;
for(int i=2;i*i<=x;i++)
{
if(x%i==0)
ans=ans/i*(i-1);
while(x%i==0)
x/=i;
}
if(x!=1)
ans=ans/x*(x-1);
return ans;
}
ll ksm(ll a,ll b,ll p)
{
ll res=1;
while(b)
{
if(b&1)
res=res*a%p;
a=a*a%p;
b>>=1;
}
return res;
}
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(!b)
{
x=1,y=0;
return a;
}
ll k=exgcd(b,a%b,y,x);
y-=a/b*x;
return k;
}
int n,T;
ll a,m;
ll work(ll a,ll p) //递归求解
{
if(p==1)
return 0;
ll m=phi(p);
ll b=work(a,__gcd(m,p))+m;
ll x,y;
ll d=exgcd(m,p,x,y);
ll k=(((x*(ksm(a,b,p)-b+p))%p+p)%p/d); //回溯求值
return k*m+b;
}
int main()
{
cin>>T;
while(T--)
{
scanf("%lld%lld",&a,&m);
printf("%lld\n",work(a,m));
}
}
1220

被折叠的 条评论
为什么被折叠?



