原根的求解及应用

原根的定义

首先引入数论中阶的定义

  • a ∈ Z , m ∈ N + a\in Z, m\in N^+ aZ,mN+,若 g c d ( a , m ) = 1 gcd(a,m)=1 gcd(a,m)=1,则称使得 a n ≡ 1 ( m o d    m ) a^n\equiv 1(\mod m) an1(modm)成立的最小正整数 n n n a a a对膜 m m m的阶

接下来是原根的定义

  • a ∈ Z , m ∈ N + a\in Z, m\in N^+ aZ,mN+,若 g c d ( a , m ) = 1 gcd(a,m)=1 gcd(a,m)=1,且 a a a m m m的阶为 φ ( m ) \varphi(m) φ(m),则 a a a为膜 m m m的原根

原根的求解

定理1:若 m ∉ { 2 , 4 } ⋃ { p α , 2 p α } m\notin \{2,4\}\bigcup\{p^\alpha,2p^\alpha\} m/{2,4}{pα,2pα}(其中p为奇素数,α为整数),则膜m不存在原根

由该定理,我们可以先求素数表,然后预处理出每个数是否有原根

定理2:膜m的原根数量级别为 O ( m 0.25 ) O(m^{0.25}) O(m0.25)

定理3:若膜m存在原根,则其有 φ ( φ ( m ) ) \varphi(\varphi(m)) φ(φ(m))个原根

假设我们已求得膜 m m m的最小原根 g g g,那么膜 m m m的所有原根就是 { g k   ∣   g c d ( k , φ ( m ) = 1 ) } \{g^k \ |\ gcd(k,\varphi(m)=1)\} {gk  gcd(k,φ(m)=1)}
所以我们可以直接从小到大枚举每个数判断其是否为膜m的原根
先得到膜m的最小原根g,再求g的幂次方以求得所有原根

为判断g是否为膜m的原根,在引入一个定理

定理4:设 a ∈ Z , m ∈ N + a\in Z, m\in N^+ aZ,mN+,若 g c d ( a , m ) = 1 gcd(a,m)=1 gcd(a,m)=1 a k ≡ 1 ( m o d    m ) a^k\equiv 1(\mod m) ak1(modm),则 k ∣ φ ( m ) k|\varphi(m) kφ(m)

易知若 g g g是膜 m m m的原根,则对所有 k < φ ( m ) k<\varphi(m) k<φ(m)均有 g k m o d    m ≠ 1 g^k \mod m \not= 1 gkmodm=1
结合定理4,我们只需要检查 φ ( m ) \varphi(m) φ(m)的真因数d,若存在 g d ≡ 1 ( m o d    m ) g^d\equiv 1(\mod m) gd1(modm)则g不是原根

进一步的,我们只需要对 φ ( m ) \varphi(m) φ(m)质因数分解,检查所有 d = φ ( m ) p i d=\frac{\varphi(m)}{p_i} d=piφ(m)即可

洛谷P6091 【模板】原根

const int maxn=1000010;
lt prim[maxn],phi[maxn],vis[maxn],cnt;
int has[maxn];
lt fac[maxn],facN;
lt rt[maxn],rtN;

lt gcd(lt a,lt b){ return b==0?a:gcd(b,a%b);}

lt qpow(lt a,lt k,lt mod)
{
	lt res=1;
	while(k){
		if(k&1) res=(res*a)%mod;
		a=(a*a)%mod; k>>=1;
	}
	return res;
}

void qPhi(lt n)
{
	phi[1]=1;
	for(lt i=2;i<=n;++i)
	{
		if(!vis[i]){ prim[++cnt]=i; phi[i]=i-1;}
		for(int j=1;j<=cnt;++j)
		{
			if(i*prim[j]>n) break;
			vis[i*prim[j]]=1;
			if(i%prim[j]==0){ phi[i*prim[j]]=phi[i]*prim[j]; break;}
			else phi[i*prim[j]]=phi[i]*phi[prim[j]];
		}
	}
}

void preWork(int lim)
{
	has[2]=has[4]=1;
	for(int i=2;i<=cnt;++i)
	{
		for(lt j=prim[i]; j<=lim; j*=prim[i]) has[j]=1; // p^α
		for(lt j=prim[i]*2; j<=lim; j*=prim[i]) has[j]=1; // 2p^α
	}
}

void div(int x)
{
	facN=0;
	for(int i=2;i*i<=x;++i)
	{
		if(x%i==0)
		{
			while(x%i==0) x/=i;
			fac[++facN]=i;
		}
	}
	if(x>1) fac[++facN]=x;
}

bool check(int g,int n)
{
	if(qpow(g,phi[n],n)!=1) return false; // g^φ(n) ≡ 1 (mod n)
	
	for(int i=1;i<=facN;++i){
		if(qpow(g,phi[n]/fac[i],n)==1) return false;
	}
	
	return true;
}

int minRt(int n)
{
	div(phi[n]); // 对φ(n)质因数分解并将质因子存在fac[]里
	for(int i=1;i<=n;++i)
	if(check(i,n)) return i;
	
	return 0;
}

void allRt(int g,int n)
{
	rtN=0;
	lt t=1;
	for(int i=1;i<=phi[n];++i)
	{
		t=t*g%n;
		if(gcd(i,phi[n])==1) rt[++rtN]=t;
	}
}

int main()
{
	qPhi(maxn-10); // 质数表和phi
    preWork(maxn-10); // 预处理每个数是否有原根
	
	int T=read();
    while(T--)
    {
    	int n=read(),d=read();
    	if(!has[n])
		{
			printf("0\n\n");
    		continue;
		}
		
		lt g=minRt(n); // 求最小原根
		allRt(g,n); // 求所有原根
		
		printf("%d\n",rtN);

		sort(rt+1,rt+1+rtN);
		for(int i=d;i<=rtN;i+=d)
		printf("%d ",rt[i]);
		
		printf("\n");
	}
	return 0;
} 

原根的应用

NTT

对于特定的膜数(一般是 P = r 2 k + 1 P=r2^k+1 P=r2k+1),例如P=998244353
可以证明膜P的原根g满足 g P − 1 n g^{\frac{P-1}{n}} gnP1与n次单位根 w n = e 2 π i n w_n=e^{\frac{2\pi i}{n}} wn=en2πi有相同性质

因此可以将FFT中的n次单位根用原根替代,得到可以在膜意义下求值、插值的NTT
快速数论变换NTT

指标函数/离散对数

首先引入简化剩余系的定义

在与模m互素的全体剩余类中,从每个类各任取一个数组成的集合,称为模m的一个简化剩余系

易知模m的既约剩余系中的元素的个数为 φ ( m ) \varphi(m) φ(m)

而原根有如下定理

g g g对膜 m m m的阶为 δ \delta δ,则 g 0 , g 1 , . . . , g δ − 1 g^0,g^1,...,g^{\delta-1} g0,g1,...,gδ1在膜m意义下互不相同

由该定理可得推论

若g为模m的原根,则 { g 0 , g 1 , g 2 , … … g φ ( m ) − 1 } \{g^0,g^1,g^2,……g^{φ(m)-1}\} {g0,g1,g2,……gφ(m)1}组成模m的一个简化剩余系

定义指标函数 I ( x ) I(x) I(x)满足 g I ( x ) ≡ x ( m o d m ) g^{I(x)}\equiv x \pmod m gI(x)x(modm)
那么有 I ( g x m o d    m ) = x I(g^x \mod m)=x I(gxmodm)=x

该函数也称为离散对数,他和对数函数有很多相同性质
I ( x y ) = I ( x ) + I ( y ) I(xy)=I(x)+I(y) I(xy)=I(x)+I(y)
I ( x a ) = a I ( x ) I(x^a)=aI(x) I(xa)=aI(x)

由此可以解决一些需要在膜意义下进行对数运算的问题
例如求解同余方程 x A ≡ B ( m o d    C ) x^A\equiv B(\mod C) xAB(modC),其中C为素数(假设离散对数已知,实际中可用BSGS求解)

首先求得 B B B的离散对数 I ( B ) I(B) I(B),由定义知其满足 g I ( B ) ≡ B ( m o d    C ) g^{I(B)}\equiv B(\mod C) gI(B)B(modC)
又由原根定义有 g φ ( C ) = g C − 1 ≡ 1 ( m o d    C ) g^{\varphi(C)}=g^{C-1}\equiv 1(\mod C) gφ(C)=gC11(modC)

因此有 g I ( B ) + ( C − 1 ) y ≡ B ( m o d    C ) g^{I(B)+(C-1)y}\equiv B(\mod C) gI(B)+(C1)yB(modC)
将该式带入原方程得 x A ≡ g I ( B ) + ( C − 1 ) y ( m o d    C ) x^A\equiv g^{I(B)+(C-1)y} (\mod C) xAgI(B)+(C1)y(modC)
两边同时取以g为底膜C意义下的离散对数得 A I ( x ) ≡ I ( B ) + ( C − 1 ) y ( m o d    φ ( C ) ) A I(x)\equiv I(B)+(C-1)y (\mod \varphi(C)) AI(x)I(B)+(C1)y(modφ(C))

当y取不同值时,可求出不同的 I ( x ) I(x) I(x),计算 x = g I ( x ) m o d    C x=g^{I(x)}\mod C x=gI(x)modC即可求得x
易知x共有 g c d ( A , C − 1 ) gcd(A,C-1) gcd(A,C1)个不同解

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值