阶,原根,指标和 N N N次剩余
阶
阶的定义
设 a a a, p p p是互质整数,存在 x x x满足 a x ≡ 1 m o d p a^x\equiv 1\mod p ax≡1modp,最小的满足条件的正整数 x x x称为 a a a模 p p p的阶,记为 O r d p ( a ) Ord_p(a) Ordp(a)
性质
性质一
设 a a a, p p p是互质整数,存在 x ′ x' x′满足 a x ′ ≡ 1 m o d p a^{x'}\equiv 1\mod p ax′≡1modp,则 O r d p ( a ) ∣ x ′ Ord_p(a)|x' Ordp(a)∣x′
证明
反证法
设 a a a, p p p是互质整数,存在整数 x ′ x' x′满足 a x ′ ≡ 1 m o d p a^{x'}\equiv 1\mod p ax′≡1modp且 O r d p ( a ) ∤ x ′ Ord_p(a)\not|x' Ordp(a)∣x′
设 x ≡ x ′ m o d O r d p ( a ) x\equiv x'\mod Ord_p(a) x≡x′modOrdp(a)且 1 ≤ x < O r d p ( a ) 1\leq x< Ord_p(a) 1≤x<Ordp(a)
显然 a x ≡ 1 m o d p a^{x}\equiv 1\mod p ax≡1modp,与 O r d Ord Ord的定义矛盾
性质二
设 a a a, p p p是互质整数, O r d p ( a ) ∣ φ ( p ) Ord_p(a)|\varphi(p) Ordp(a)∣φ(p)
证明
a φ ( p ) ≡ 1 m o d p a^{\varphi(p)}\equiv 1\mod p aφ(p)≡1modp
原根
原根的定义
设 a a a, p p p是互质整数, O r d p ( a ) = φ ( p ) Ord_p(a)=\varphi(p) Ordp(a)=φ(p),则称 a a a是模 p p p的一个原根
性质
性质一
只有 2 , 4 , p k , 2 p k 2,4,p^k,2p^k 2,4,pk,2pk有原根( p p p为奇素数)
性质二
一个数 p p p若存在原根,则有 φ ( φ ( p ) ) \varphi(\varphi(p)) φ(φ(p))个原根
证明
假设已经找到了一个原根 g g g,那么对于所有 gcd ( x , φ ( p ) ) = 1 \gcd(x,\varphi(p))=1 gcd(x,φ(p))=1的 x x x, g x g^x gx也是 p p p的原根
性质三
若 a a a是 p p p的原根, a 0 , a 1 . . . a φ ( p ) − 1 a^0,a^1...a^{\varphi(p)-1} a0,a1...aφ(p)−1两两不同,即构成了模 p p p的简化剩余系
如何求原根
先求最小正原根
从小到大枚举 g g g并检验 g g g是否是 p p p的原根,枚举次数是 p 0.25 p^{0.25} p0.25级别的
如何检验?
满足 ∀ i < v a r p h i ( p ) \forall i<varphi(p) ∀i<varphi(p), g i ≠ 1 m o d p g^i\not=1\mod p gi=1modp,且 g φ ( p ) ≡ 1 m o d p g^{\varphi(p)}\equiv 1\mod p gφ(p)≡1modp
根据阶的性质,只需要检验 φ ( p ) \varphi(p) φ(p)的所有真因数即可,考虑检验所有真因数的倍数
设 φ ( p ) = ∏ i q i c i \varphi(p)=\prod_iq_i^{c_i} φ(p)=∏iqici
∀ i \forall i ∀i,检验 φ ( p ) q i \frac{\varphi(p)}{q_i} qiφ(p)即可
指标
定义
设 g g g是 p p p的原根, a a a, p p p是互质整数,存在唯一的整数 x x x满足 g x ≡ a m o d p g^x\equiv a\mod p gx≡amodp,称 x x x为以 g g g为底对模 p p p的一个指标,记为 x = i n d g a x=ind_ga x=indga
性质
性质一
若 a ≡ b m o d p a\equiv b\mod p a≡bmodp,则 i n d g a ≡ i n d g b m o d φ ( p ) ind_ga\equiv ind_gb\mod \varphi(p) indga≡indgbmodφ(p)
性质二
i n d g ( a b ) ≡ i n d g ( a ) + i n d g ( b ) m o d φ ( p ) ind_g(ab)\equiv ind_g(a)+ind_g(b)\mod \varphi(p) indg(ab)≡indg(a)+indg(b)modφ(p)
性质三
i n d g ( a k ) ≡ k × i n d g ( a ) m o d φ ( p ) ind_g(a^k)\equiv k\times ind_g(a)\mod \varphi(p) indg(ak)≡k×indg(a)modφ(p)
如何求指标
就是求离散对数,直接 B S G S BSGS BSGS
BSGS
求 x x x满足 A x ≡ B m o d p A^x\equiv B\mod p Ax≡Bmodp,满足 gcd ( A , p ) = 1 \gcd(A,p)=1 gcd(A,p)=1
显然 x ∈ [ 0 , p ) x\in [0,p) x∈[0,p)
设 M = ⌈ ( p ) ⌉ M=\lceil \sqrt(p)\rceil M=⌈(p)⌉
设 x = i × M − c , c ∈ [ 0 , M ) x=i\times M-c,c\in [0,M) x=i×M−c,c∈[0,M)
A
i
×
M
−
c
≡
B
m
o
d
p
A^{i\times M-c}\equiv B\mod p
Ai×M−c≡Bmodp
A
i
×
M
≡
B
×
A
c
m
o
d
p
A^ {i\times M}\equiv B\times A^c\mod p
Ai×M≡B×Acmodp
枚举
c
c
c,把
B
×
A
c
B\times A^c
B×Ac插进一个map
,最后枚举
i
i
i求解即可
N N N次剩余
求所有 x x x满足 x A ≡ B m o d C x^A\equiv B\mod C xA≡BmodC
分解问题
考虑将 C C C质因数分解
子问题为求所有 x x x满足 x A ≡ B m o d p i α i x^A\equiv B\mod p_i^{\alpha_i} xA≡Bmodpiαi
每个方程可能有多种解,每个方程中选一个解,这样每组选择方法唯一对应一种答案,用 E x C r t / C r t ExCrt/Crt ExCrt/Crt合并即可
处理每个 x A ≡ B m o d p α x^A\equiv B\mod p^\alpha xA≡Bmodpα
若 gcd ( B , p α ) = 1 \gcd(B,p^\alpha)=1 gcd(B,pα)=1
设
M
=
p
α
M=p^\alpha
M=pα,
g
g
g是
M
M
M的原根,
y
=
i
n
d
M
x
,
z
=
i
n
d
M
B
y=ind_Mx,z=ind_MB
y=indMx,z=indMB
A
×
y
≡
z
m
o
d
φ
(
M
)
A\times y\equiv z\mod \varphi(M)
A×y≡zmodφ(M)
若
z
≡
0
m
o
d
φ
(
M
)
z\equiv 0\mod \varphi(M)
z≡0modφ(M)
,设
q
w
q
=
gcd
(
A
,
φ
(
M
)
)
qwq=\gcd(A,\varphi(M))
qwq=gcd(A,φ(M))
y
≡
0
m
o
d
φ
(
M
)
q
w
q
y\equiv 0\mod \frac{\varphi(M)}{qwq}
y≡0modqwqφ(M)
y
∈
[
0
,
φ
(
M
)
)
y\in [0,\varphi(M))
y∈[0,φ(M)),共有
q
w
q
qwq
qwq组解
否则,设
q
w
q
=
gcd
(
A
,
z
,
φ
(
M
)
)
qwq=\gcd(A,z,\varphi(M))
qwq=gcd(A,z,φ(M))
y
≡
z
q
w
q
×
(
A
q
w
q
)
−
1
m
o
d
φ
(
M
)
q
w
q
y\equiv \frac{z}{qwq}\times (\frac{A}{qwq})^{-1}\mod\frac{\varphi(M)}{qwq}
y≡qwqz×(qwqA)−1modqwqφ(M)
x
≡
g
y
m
o
d
M
x\equiv g^y\mod M
x≡gymodM
y
∈
[
0
,
φ
(
M
)
)
y\in [0,\varphi(M))
y∈[0,φ(M)),有
q
w
q
qwq
qwq组解
若 gcd ( B , p α ) = p q ( 1 ≤ q < α ) \gcd(B,p^\alpha)=p^q(1\leq q<\alpha) gcd(B,pα)=pq(1≤q<α)
x A ≡ B m o d p α x^A\equiv B\mod p^\alpha xA≡Bmodpα
设 B = z × p q B=z\times p^q B=z×pq, x = y × p a x=y\times p^a x=y×pa
(
y
×
p
a
)
A
≡
z
×
p
q
m
o
d
p
α
(y\times p^a)^A\equiv z\times p^q\mod p^\alpha
(y×pa)A≡z×pqmodpα
y
A
×
p
a
A
≡
z
×
p
q
m
o
d
p
α
y^A\times p^{aA}\equiv z\times p^q\mod p^\alpha
yA×paA≡z×pqmodpα
显然,
A
∣
q
A|q
A∣q,反之无解
求解 y A ≡ z m o d p α − q y^A\equiv z\mod p^{\alpha-q} yA≡zmodpα−q, x = y × p q A x=y\times p^\frac{q}{A} x=y×pAq即可
每组 y A ≡ z m o d p α − q A y^A\equiv z\mod p^{\alpha-\frac{q}{A}} yA≡zmodpα−Aq的解唯一对应一组 x A ≡ B m o d p α x^A\equiv B\mod p^{\alpha} xA≡Bmodpα的解
所以每个 y y y分别对应 p q − q A p^{q-\frac{q}{A}} pq−Aq个 x x x
若 B ≡ 0 m o d p α B\equiv 0\mod p^\alpha B≡0modpα
x ≡ 0 m o d p ⌈ α A ⌉ x\equiv 0\mod p^{\lceil\frac{\alpha}{A}\rceil} x≡0modp⌈Aα⌉
x ∈ [ 0 , p α ) x\in [0,p^\alpha) x∈[0,pα),共有 p α − ⌈ α A ⌉ p^{\alpha-\lceil\frac{\alpha}{A}\rceil} pα−⌈Aα⌉组解
若 p p p为 2 2 2
x A ≡ B m o d 2 α x^A\equiv B\mod 2^{\alpha} xA≡Bmod2α
求出 y A ≡ B m o d 2 α − 1 y^A\equiv B \mod 2^{\alpha-1} yA≡Bmod2α−1, x = y x=y x=y或 x = y + 2 α − 1 x=y+2^{\alpha-1} x=y+2α−1
如何用 E x C r t ExCrt ExCrt合并答案?
以上选出的答案都为同余方程的形式,考虑如何合并两个同余方程
{
x
≡
c
1
m
o
d
p
1
x
≡
c
2
m
o
d
p
2
\left\{\begin{aligned}x\equiv c_1\mod p_1\\x\equiv c_2\mod p_2\end{aligned}\right.
{x≡c1modp1x≡c2modp2
c
1
+
p
1
×
k
1
=
c
2
+
p
2
×
k
2
c_1+p_1\times k_1=c_2+p_2\times k_2
c1+p1×k1=c2+p2×k2
p
1
×
k
1
−
p
2
×
k
2
≡
c
2
−
c
1
p_1\times k_1-p_2\times k_2\equiv c_2-c_1
p1×k1−p2×k2≡c2−c1
设
q
w
q
=
gcd
(
p
1
,
p
2
)
qwq=\gcd(p_1,p_2)
qwq=gcd(p1,p2),若
q
w
q
∤
(
c
2
−
c
1
)
qwq\not|(c_2-c_1)
qwq∣(c2−c1),无解
否则,令 P 1 = p 1 q w q , P 2 = p 2 q w q , C = c 2 − c 1 q w q P_1=\frac{p_1}{qwq},P_2=\frac{p_2}{qwq},C=\frac{c_2-c_1}{qwq} P1=qwqp1,P2=qwqp2,C=qwqc2−c1
求 k 1 k_1 k1, k 1 ≡ C P 1 m o d P 2 k_1\equiv\frac{C}{P_1}\mod P_2 k1≡P1CmodP2
x
0
=
c
1
+
k
1
×
p
1
x_0=c_1+k_1\times p_1
x0=c1+k1×p1
=
c
1
+
(
k
1
+
p
2
q
w
q
k
2
)
×
p
1
=c_1+(k_1+\frac{p_2}{qwq}k_2)\times p_1
=c1+(k1+qwqp2k2)×p1
x
≡
k
1
×
p
1
+
c
1
m
o
d
p
1
p
2
gcd
(
p
1
,
p
2
)
x\equiv k_1\times p_1+c_1\mod \frac{p_1p_2}{\gcd(p_1,p_2)}
x≡k1×p1+c1modgcd(p1,p2)p1p2
代码
#include<bits/stdc++.h>
using namespace std;
#define Ri register
template<typename T>inline T read(Ri T& t)
{Ri T f=1;Ri char ch=getchar();t=0;
while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
while(ch>='0'&&ch<='9')t=t*10+ch-'0',ch=getchar();t*=f;return t;}
template <typename T,typename...Args>
inline void read(T&t,Args&...args)
{read(t);read(args...);}
#define ll long long
inline ll power(Ri ll x,Ri ll k,Ri ll p=1e18)
{
ll re=1;
for(;k;k>>=1,x=x*x%p)if(k&1)re=re*x%p;
return re;
}
inline int BSGS(ll b,ll n,ll p)//B^i=n/mod p
{
if(n==1)return 0;
map<int,int> mp;
int m=ceil(sqrt(p))+1;
ll t=n;
for(int i=0;i<=m;i++,t=t*b%p)mp[t]=i;
t=power(b,m,p);
for(ll i=1,s=t;i<=m;i++,s=s*t%p)
if(mp.count(s))
return i*m-mp[s];
}
inline ll gcd(ll a,ll b)
{
if(b==0)return a;
return gcd(b,a%b);
}
int pri[1000005],pri_top;
bool check(int n,int g,int varphi)
{
if(power(g,varphi,n)!=1)return 0;
for(int i=1;i<=pri_top;i++)
if(power(g,varphi/pri[i],n)==1)
return 0;
return 1;
}
int get_g(int n,int varphi)
{
int phi=varphi;
pri_top=0;
for(int i=2;i*i<=phi;i++)
{
if(phi%i)continue;
pri[++pri_top]=i;
while(phi%i==0)phi/=i;
}
if(phi!=1)pri[++pri_top]=phi;
// printf("varphi=%d,phi:",varphi[n]);for(int i=1;i<=pri_top;i++)printf("%d ",pri[i]);printf("\n");
int g=1;while(check(n,g,varphi)==0)g++;
return g;
}
#define Pii pair<int,int>
#define Vii vector<pair<int,int> >
int Exgcd(int a,int b,ll & x,ll & y)
{
if(b==0)return x=1,y=0,a;
int re=Exgcd(b,a%b,x,y);
ll qwq=x;
x=y;y=qwq-(a/b)*y;
return re;
}
int Inv(int a,int p)
{
ll x,y;
Exgcd(a,p,x,y);
return (x%p+p)%p;
}
Vii SOLVE(int A,int B,int P,int Alpha)//x^A=B mod P^Alpha
{
int M=power(P,Alpha);B%=M;
// printf("SOLVE:x^%d=%d mod %d^%d\n",A,B,P,Alpha);
if(P==2)
{
if(Alpha==0)return {make_pair(0,1)};
Vii pre=SOLVE(A,B,2,Alpha-1);
Vii re;
for(auto i:pre)
{
ll qwq=i.first;
if(power(qwq,A,M)==B)re.push_back(make_pair(qwq,M));
qwq=(qwq+M/2)%M;
if(power(qwq,A,M)==B)re.push_back(make_pair(qwq,M));
}
return re;
}
Vii re;int var_M=M/P*(P-1);
if(B==0)
{
int qwq=power(P,ceil((double)Alpha/A));
for(int i=0;i*qwq<M;i++)
re.push_back(make_pair(i*qwq,M));
return re;
}
if(gcd(B,M)==1)
{
int g=get_g(M,var_M);
// printf("g=%d var_M=%d\n",g,var_M);
int z=BSGS(g,B,M);
if(z==0)
{
int qwq=gcd(A,var_M);
for(int i=0;i<var_M;i+=var_M/qwq)
re.push_back(make_pair(power(g,i,M),M));
return re;
}
int qwq=gcd(A,gcd(z,var_M));
// printf("%d^%d=%d mod %d\n",g,z,B,M);
if(gcd(A/qwq,var_M/qwq)!=1)return {};
int y=(ll)z/qwq*Inv(A/qwq,var_M/qwq)%(var_M/qwq);
for(int i=0;i<qwq;i++)
// printf("%d^%d\n",g,y+var_M/qwq*i),
re.push_back(make_pair(power(g,y+var_M/qwq*i,M),M));
}
else
{
int gc=gcd(B,M);
int q=1,qaq=P;
while(qaq!=gc)
qaq=qaq*P,q++;
if(q%A)return {};
int z=B/qaq;
Vii pre=SOLVE(A,z,P,Alpha-q);
int qwq=power(P,q/A,M);
int qAq=power(P,q-q/A);
int QaQ=power(P,Alpha-q);
for(auto i:pre)
for(ll j=0;j<qAq;j++)
re.push_back(make_pair((i.first+j*QaQ%M)*qwq%M,M));
}
// printf("SOLVE:x^%d=%d mod %d^%d\n",A,B,P,Alpha);
// for(auto i:re)printf("%lld mod %lld\n",i.first,i.second);
return re;
}
Vii solution[1005];
int solution_top;
vector<long long> ans;
bool without_ans;
void DFS(int now,ll m,ll p)
{
if(without_ans)return;
if(now>solution_top)return ans.push_back(m),void();
for(auto i:solution[now])
{
ll qwq=gcd(p,i.second);
ll C=(i.first-m%i.second+i.second)%i.second;
if(C%qwq)return without_ans=1,ans={},void();
ll P1=p/qwq,P2=i.second/qwq,c=C/qwq;
ll k1=c*Inv(P1,P2)%P2;
ll p2=p*i.second/gcd(p,i.second);
DFS(now+1,(k1*p+m)%p2,p2);
}
}
void solve(int A,int B,int C)//x^A=b mod C
{
int M=C;solution_top=0;
for(int i=2;i*i<=M;i++)
if(M%i==0)
{
int sum=0;
while(M%i==0)
M/=i,sum++;
solution[++solution_top]=SOLVE(A,B,i,sum);
// printf("Devided Question:x^%d=%d mod %d^%d\n",A,B,i,sum);
// for(auto i:solution[solution_top])printf("%lld mod %lld\n",i.first,i.second);
}
if(M!=1)solution[++solution_top]=SOLVE(A,B,M,1);
// printf("Devided Question:x^%d=%d mod %d^%d\n",A,B,M,1);
// for(auto i:solution[solution_top])printf("%lld mod %lld\n",i.first,i.second);
ans.clear();
without_ans=0;
DFS(1,0,1);
sort(ans.begin(),ans.end());
printf("%d\n",ans.size());
if(ans.size()==0)return;
for(auto i:ans)printf("%lld ",i);
printf("\n");
}
int main()
{
int T;
read(T);
while(T--)
{
int A,B,C;
read(A,C,B);
solve(A,B,C);
}
return 0
}