我的坟头应该开满玫瑰吗?|

YYYmoon

园龄:1年粉丝:20关注:41

原根

由欧拉定理知,若 (a,m)=1 ,则 aφ(m)1(modm)

因此满足 an1(modm)最小正整数 n 存在,这个 n 称作 am 的阶,记作 δm(a)ordm(a)

此外还有“半阶”的概念, δ 表示满足 an1(modm) 的最小的n

在互质的条件下,阶一定存在,半阶不一定存在

性质1

a,a2,,aδm(a)m 两两不同余。

证明:

假设存在 ij ,且 aiaj(modm) ,则有 a|ij|1(modm) .

但显然有 0<|ij|<δm(a) ,这与阶的最小性矛盾。

性质2

an1(modm),则 δm(a)n.

证明:

n 除以 δm(a) 做带余除法,设 n=δm(a)q+r,0r<δm(a).

r>0,则 arar(aδm(a))qan1(modm)

这与阶的最小性矛盾,故 r=0 .

  • 据此还有:若 apaq(modm) ,则有 pq(modδm(a)).

性质3

mNa,bZ(a,m)=(b,m)=1,则

δm(ab)=δm(a)δm(b) 等价于 (δm(a),δm(b))=1

性质4

kNmNaZ(a,m)=1,则 δm(ak)=δm(a)(δm(a),k)

性质3,4证明略,可以看oi-wiki。

原根

mNgZ. 若 (g,m)=1,且 δm(g)=φ(m),则称 g 为模 m 的原根。

特别的,当 m 是质数时,由阶的性质1得,我们有 gimodm,i[1,m1] 的结果互不相同。(这里经常对 i 的范围有两种表述,i[1,m1]i[0,m1) 。仔细想想这两者是等价的。首先,在模 m 意义下我们可能得到的非零取模结果只有 1,2,...,m1 ,且 g0=1,gm11(modm),也就是这个在哪边取这个 1 的一个问题。

在抽象代数中,原根就是循环群的生成元。这个概念只在模 m 缩剩余系关于乘法形成的群中有「原根」这个名字,在一般的循环群中都称作「生成元」。
并非每个模 m 缩剩余系关于乘法形成的群都是循环群,存在原根就表明它同构于循环群,如果不存在原根就表明不同构。 ——引自oi-wiki

原根判定定理

m3,(g,m)=1,则 g 是模 m 的原根的充要条件是,

对于 φ(m) 的每个质因数 p,都有gφ(m)p1(modm).

证明:必要性显然,否则不符合最小性。

充分性考虑反证,假设存在一个g,满足该条件但不是原根。

由于 gφ(m)1(modm),带入阶的性质2,会有 δm(g)|φ(m) .

但,g 不是 m 的原根,所以 δm(g)φ(m) ,所以一定存在一个 φ(m) 的质因子 p 使得 δm(g)|φ(m)p ,矛盾。

原根个数

若一个数 m 有原根,则它原根的个数为 φ(φ(m)).

证明:

若 m 有原根 g,由阶的性质4得:

δm(gk)=δm(g)gcd(δm(g),k)=φ(m)gcd(φ(m),k)

所以若 gcd(φ(m),k)=1 ,则有 δm(gk)=φ(m),此时 gk 也是 m 的原根。这样的 k 有 φ(φ(m)) 个。

注意到,这些 gk 模m是互不同余的(由阶的性质1),所以直接算就行。

原根存在定理

一个数 m 存在原根当且仅当 m=2,4,pα,2pα,其中 p 为奇质数,αN.

证明极为复杂,因此略。

求原根

经某些dalao证明,质数 p 的最小原根是 O(p0.25)级别的。

我们首先判断该数字是否有原根,然后暴力枚举判断最小原根,最后用原根个数定理中的条件找出剩下的 gk 这些原根即可。

我们寻找n的最小原根的复杂度是 O(n0.25log2n),实际上复杂度瓶颈在最后sort的 O(nlogn)

[模板] 原根
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
int T,n,d,phi[maxn],p[maxn],cnt,vis[maxn];
int rt[maxn],tot,f[maxn],ans[maxn],num;
void init(){
	phi[1]=1;
	for(int i=2;i<=maxn-5;i++){
		if(!vis[i]) p[++cnt]=i,phi[i]=i-1;
		for(int j=1;j<=cnt&&i*p[j]<=maxn-5;j++){
			vis[i*p[j]]=1;
			if(i%p[j]==0){
				phi[i*p[j]]=phi[i]*p[j];
				break;
			} else phi[i*p[j]]=phi[i]*(p[j]-1);
		}
	}
	rt[2]=rt[4]=1;
	for(int i=2;i<=cnt;i++){
		for(long long j=p[i];j<=maxn-5;j*=p[i]) rt[j]=1;//小心炸int 
		for(long long j=2*p[i];j<=maxn-5;j*=p[i]) rt[j]=1;
	}
}
int gcd(int x,int y){
	if(y==0) return x;
	return gcd(y,x%y);
}
int qpow(int x,int y,int p){
	int res=1;
	while(y){
		if(y&1) res=1ll*res*x%p;
		x=1ll*x*x%p;
		y>>=1;
	}
	return res;
}
void div(int n){
	tot=0;
	for(int i=2;i<=n/i;i++){
		if(n%i==0){
			f[++tot]=i;
			while(n%i==0) n/=i;
		} 
	}
	if(n>1) f[++tot]=n;
}
bool check(int x,int n){
	if(gcd(x,n)!=1) return 0;
	for(int i=1;i<=tot;i++){
		if(qpow(x,phi[n]/f[i],n)==1) return 0;
	}
	return 1;
} 
int findrt(int n){
	for(int i=1;i<n;i++){
		if(check(i,n)) return i;
	}
	return 0;
}
void getrt(int n,int x){
	int y=1; num=0;
	for(int i=1;i<=phi[n];i++){
		y=1ll*y*x%n;
		if(gcd(i,phi[n])==1) ans[++num]=y;
	}
}
int main(){
	init();
	scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&d);
		if(rt[n]){
			div(phi[n]);
			int mn=findrt(n);
			getrt(n,mn);
			sort(ans+1,ans+num+1);
			printf("%d\n",num);
			for(int i=d;i<=num;i+=d) printf("%d ",ans[i]);
			printf("\n");
		} else printf("0\n\n");
	}
	return 0;
}

指标

指标,又称离散对数,就是在模意义下进行的对数运算。设 pN+ 且有原根 g ,对于满足 gcd(a,p)=1 的整数 a,必然存在唯一的 0k<φ(p) 使得 gka(modp)

则称 kap 的指标,记作 k=ind(a)=γ(a)

性质和普通对数类似

  • ab(modp) ,则 γ(a)γ(b)(modφ(p))

  • γ(ab)=γ(a)+γ(b)

  • γ(an)=nγ(a)(modφ(p))

bzoj 1420. Discrete Root

它问的是 xka(modp) 的所有 x

如果你对算法比较熟悉,就会想到BSGS算法:求 axb(modp) 的最小 x

那么我们试图把在底数上的未知数转化到指数上。

已知 p 为质数,则必然存在原根,且 δm(a)=φ(p)=p1

由阶的性质1,对于 ix|1x<p ,存在唯一的 jx|1x<p 使得 gji(modp) ,我们不妨就令这个映射为 j=f(i) .

那么方程转化为 xk (gf(x))k (gk)f(x) a(modp)

我们就可以用 BSGS 求出 f(x) 进而求出 gf(x)

还有一种方法是用指标转化,直接就出来了(但笔者在写这题的时候还没学指标

bzoj 2219. 数论之神

跟上一题的区别在于这个模数不一定有原根,然后我们就需要一系列的分解质因数和化为同余方程组。需要一个巨大的分讨来求解因数个数。

我刚把那一坨latex打完,直接退出,直接完蛋。。全**丢了,气死了

本文作者:YYYmoon

本文链接:https://www.cnblogs.com/YYYmoon/p/18718153

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   YYYmoon  阅读(8)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起