本文中,若无特殊说明,m 代表正整数,p 代表质数。
事实上,在题目中我们大多数情况下都是讨论对质数取模的情况。
阶
定义
若 (a,m)=1,满足 an=1(modm) 的最小的 n 称为 a 模 m 的阶,记作 δma。
如果 (a,m)=1 不互质,那么不难发现,不存在 n,使得 an=1(modm),故我们不定义 a 模 m 的阶。
性质
本节中 a,b 均与 m 互质。
- a,a2,…,aδma 模 m 两两不同。
【引理 1】完全剩余系中与 m 互质的剩余类所构成的系称为缩系,缩系内四则运算均封闭。
(证明略)
性质 1 证明:
用反证法,假设存在 1≤i<j≤δma,使得 ai≡aj(modm),因为 ai 和 aj 均与 m 互质,存在逆元,故 aj−i≡1(modm),而 j−i<δma,故 δma 不是最小,矛盾!
- 若 an≡1(modm)⟺n≡0(modδma)
【引理 2】若 ax≡ay≡1(modm),则 agcd(x,y)≡1(modm)。
【引理 2 证明】因为存在逆元,我们可知 aAx+By≡1(modm) (A,B∈Z)。由裴蜀定理,gcd(x,y) 能表示为 x,y 的线性组合,故引理成立。
性质 2 证明:
先证 ⇐:若 n≡0(modδma),设 n=kδma (k∈N∗),an=(aδma)k≡1(modm) 。
再证 ⇒:用反证法,假设存在 an≡1 且 n 不是 δma 的倍数,则 gcd(n,δma),由引理 2 可知 agcd(n,δma)≡1(modm),故 δma 不是最小,矛盾!
- ax≡ay(modm)⟺x≡y(modδma)。
性质 3 证明:
先证 ⇐:若 x≡y(modδma),则 ax−y≡1(modm),则 ax≡ay(modm)。
再证 ⇒:因为 ax−y≡1(modm),由性质 2 可知,x−y 为 δma 的倍数,故成立。
- δm(ab)=δmaδmb⟺(δma,δmb)=1。
性质 4 证明:
-
先证 ⇒:
因为 aδma≡1(modm),bδmb≡1(modm),故 ab[δma,δmb]≡1(modm)
由性质 2 可知,δm(ab)∣[δma,δmb],即 δmaδmb∣[δma,δmb]。
故 (δma,δmb)=1。
-
再证 ⇐:
因为 aδma≡1(modm),bδmb≡1(modm),故 abδmaδmb≡1(modm),即 δmaδmb∣δm(ab) (∗)。
又 1≡(ab)δm(ab)δmb≡(a)δm(ab)δmb(modm),可知 δma∣δm(ab)δmb。
结合 (δma,δmb)=1,得 δma∣δm(ab)。
同理 δmb∣δm(ab),故 δmaδmb∣δm(ab) (△)。
由 (∗),(△) 两式得 δm(ab)=δmaδmb。
- δm(ak)=(δma,k)δma。
性质 5 证明:
设 δm(ak)=d,有 (ak)d≡1(modm)。
即要找到最小的 d 满足 akd≡1(modm)。
由性质 2 可知,我们需要让 kd≡0(modδma)。
不难发现最小的 d 即为 (δma,k)δma。
求法
如果求 a 的阶(a 与 m 互质),初始令阶 x 为 φ(m),对 φ(m) 的每一个质因数,如果除了它之后仍然有 ax≡1(modm),则不断除掉这个质因数,最后得到的就是它的阶。
正确性说明:
假设最后结果为 d。
显然有 ad≡1(modm),只需证明不存在更小的 x 使得 ax≡1(modm) 即可。
如果 δma=d,则存在 f∣d,ad/f≡1(modm),显然与我们的算法矛盾,故该算法能正确求出阶。
复杂度 O(m+log2m)。(预处理质因数 m,有 logm 个质因数,每次快速幂判断复杂度为 logm).
参考代码:
1 2
| ll ord = phi(m); for(auto f:fp)while(ord%f==0 && ksm(a,ord/f,m)==1)ord/=f;
|
其中 fp
是存有 φ(m) 的质因数的 vector
,函数 ksm(a,b,p)
表示 abmodm 的值。
原根
原根和阶是紧密相关的概念。
定义
若 δm(g)=φ(m),称 g 为模 m 的原根。
性质
-
(原根判定定理)g 是 m的原根⟺∀p∣φ(m),ggφ(m)≡1(modm) 且 (g,m)=1。
-
(原根个数定理)若 m 存在一个原根 g,则所有原根可以表示为 gk,其中 (k,φ(m))=1。故原根个数有 φ(φ(m))个。
-
(原根存在定理)m 存在原根当且仅当 m=2,4 或 m=pα,2pα,其中
p 为质数,α∈N∗。
-
若一个质数 p 存在原根,其最小原根 gmin=O(p1/4)。(这并不意味着存在一个小于等于 p1/4 的原根)
求法
- 判断原根是否存在;O(n) (或预处理 O(n))
- 若存在,从 1 开始枚举与 n 互质的数,找到最小原根;O(n0.25log2n)
- 找出所有与 φ(n) 互质的 k,求出所有原根。O(φ(n)logφ(n))
- (对所有原根排序. O(φ(φ(n))logφ(φ(n)))。
参考代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
| #include<bits/stdc++.h> using namespace std;
using ll=long long; inline int read(){int f=1,x=0;char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)){x=x*10+c-'0';c=getchar();}return x*f;}
const int N = 1e6+5; bool vis[N]; int pri[N],cnt,phi[N]; bool have[N];
int ksm(int a,int b,int p){ int r = 1; while(b){ if(b&1)r=(ll)r*a%p; a=(ll)a*a%p; b>>=1; } return r; }
int main(){ phi[1]=1; for(int i=2;i<N;i++){ if(!vis[i])pri[cnt++]=i,phi[i]=i-1; for(int j=0;j<cnt&&i*pri[j]<N;j++){ vis[i*pri[j]]=1; if(i%pri[j]==0){ phi[i*pri[j]]=phi[i]*pri[j]; break; } phi[i*pri[j]]=phi[i]*(pri[j]-1); } } have[2]=have[4]=1; for(int i=1;i<cnt;i++){ for(ll j=pri[i];j<N;j*=pri[i])have[j]=1; for(ll j=2*pri[i];j<N;j*=pri[i])have[j]=1; }
int T=read(); while(T--){ int n=read(),d=read(); if(!have[n]){ puts("0\n"); continue; }
vector<int> fac; int P = phi[n]; for(int i=2;i*i<=P;i++){ if(P%i==0){ fac.push_back(i); while(P%i==0)P/=i; } } if(P!=1)fac.push_back(P); vector<int> g; for(int i=1;;i++){ if(__gcd(n,i)!=1)continue; bool ok = 1; for(auto p:fac) if(ksm(i,phi[n]/p,n)==1){ok=0;break;}
if(ok){ for(int k=1;k<=phi[n];k++) if(__gcd(k,phi[n])==1)g.push_back(ksm(i,k,n)); break; } } sort(g.begin(),g.end()); assert(g.size()==phi[phi[n]]); printf("%d\n",(int)g.size()); for(int i=d-1;i<g.size();i+=d)printf("%d ",g[i]); puts(""); }
return 0; }
|
离散对数
定义
当 (a,m)=1 时,若存在 ak≡b(modm),则将满足上式的最小自然数 k 称作对 m 取模下,以 a 为底 b 的离散对数,记作indab=k。
这就允许我们将模意义下的乘法化为加法,从而更方便的解决问题。
性质
- inda1=0。
- indaa=1。
- inda(xy)=indax+inday(modδma),indaxn≡nindax(modδma)。
- x≡y(modm)⟺indax=inday。
注意:在取离散对数之后,取模变为 δma,而不是原来的 m。
求法
BSGS 算法:在 O(m) 的时间内求 ax=b(modm) 的解。要求 (a,m)=1。
设 t=⌈m⌉。不妨设解 x=it−j。(0≤j≤t)
则 ait−j≡b(modm),即 ait≡baj(modm)。
求出 i,j 后就能得到答案。(互质的原因是我们推导用到了逆元)
参考代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| #include<bits/stdc++.h> using ll=long long; using namespace std; ll ksm(ll a,ll b,ll p){ ll r=1; while(b){ if(b&1)r=r*a%p; a=a*a%p; b>>=1; } return r; } int main(){ ll p,a,b; scanf("%lld%lld%lld",&p,&a,&b); ll t=ceil(sqrt(p)); map<ll,int>vis; for(ll i=0,now=b;i<=t;i++,now=now*a%p)vis[now]=i; ll at = ksm(a,t,p); for(ll i=1,now=at;i<=t;i++,now=now*at%p){ if(vis.count(now)){ printf("%lld\n",i*t-vis[now]); return 0; } } puts("no solution"); return 0; }
|
习题
P6091 【模板】原根
P3846 [TJOI2007] 可爱的质数/【模板】BSGS
[ABC335G] Discrete Logarithm Problems (参考代码)