首页 > 其他分享 >初等数论(Ⅲ):高次同余、阶和原根相关

初等数论(Ⅲ):高次同余、阶和原根相关

时间:2023-05-27 09:13:57浏览次数:38  
标签:frac text 高次 perp 阶和原 BSGS equiv 同余 mod

前言

关于高次同余方程,有 \(a^x \equiv b(\text{mod} \ p)\) 和 \(x^a \equiv b(\text{mod} \ p)\) 两种类型,后者计算起来较为麻烦,下文就分别记述这两种高次同余方程。

离散对数问题

离散对数问题是在模 \(p\) 意义下求解 \(\log_ab\),这等价于形如

\[a^x \equiv b(\text{mod} \ p) \]

的高次同余方程,其中 \(x\) 即为 \(\log_ab\),\(x\) 是一个非负整数。

当 \(a \perp b\) 时,我们可以采用 BSGS 算法解决;当 \(a \not\perp b\) 时,可以采用 exBSGS 算法求解。

BSGS

大步小步算法,英文名为 Baby Step Giant Step,简称 BSGS。适用于 \(a\perp p\) 的情况。

算法流程

由扩展欧拉定理得

\[a^x \equiv a^{x \mod \varphi(p)}(\text{mod} \ p) \]

所以 \(a^x\) 模 \(p\) 意义下的循环节就是 \(\varphi(p)\),又因 \(\varphi(p) < p\),所以考虑 \(x\in[0,p]\) ,一定能找到最小整数 \(x\)。自此,问题缩小到了 \(O(p)\) 级别。如果 \(p\leq 2^{32}\),那就超时了。这时候就要请出我们今天的主角----根号平衡闪亮登场!

我们令 \(x = im-j\),其中 \(m=\lceil \sqrt{p} \ \rceil , i\in[1,m],j\in[0,m-1]\)。这样分配,\(im-j\) 就能取遍 \([1,p]\) 了,如果 \(x=0\),说明 \(b=1\),特判一下就行了。

我们把上式转换一下,则有

\[a^{im-j} \equiv b(\text{mod} \ p) \]

因为 \(a\perp p\) ,所以

\[(a^{m})^i \equiv ba^j(\text{mod} \ p) \]

是一个等价转换(除回去模数不变)。

然后枚举 \(i,j\)。

  1. 先枚举 \(j\),把 \((ba^j \ \text{mod} \ p,j)\) 插入一个 Hash 表。如果 \(ba^j \ \text{mod} \ p\) 出现相等的情况,为了求最小解,显然用更大的 \(j\) 替代小的解。

  2. 然后枚举 \(i\) ,计算 \((a^m)^i \ \text{mod} \ p\),到 Hash 表中判断是否有相等的 key,因为 \(i\times m\) 的变化量是比 \(j\) 大的,所以我们找到第一个就可以结束程序,最小的 \(x=im-j\) 就出来了。

这样,枚举 \(i,j\) 的次数都是 \(\sqrt p\) 的,总算法的复杂度也就是 \(O(\sqrt{p\ })\) 的。

map <int,int> Hash;

signed main()
{
	mod = read() , a = read(), b = read();
	if(b == 1) { return printf("0"),0; }//特判一下
	m = ceil(sqrt(mod));
	Hash[b] = 0/*j取0,ba^j就是b*/ , t = b;
	for(re int i=1;i<m;i++)//枚举ba^j
	{
		t = t * a % mod;
		Hash[t] = i;
	}
    
    
	val = ksm(a,m) , t = 1;
	for(re int i=1;i<=m;i++)//枚举(a^m)^i
	{
		t  = t * val % mod;
		if(Hash.count(t)) {  return printf("%lld",i*m-Hash[t]),0; }//有值直接输出
	}
	printf("no solution");
	return 0;
}

exBSGS

当 \(a\not\perp p\) 的时候,我们的 exBSGS 就要出场了。

化未知为已知,我们思考怎么操作能让 \(a,p\) 互质。

首先,原方程可以写作

\[a \cdot a^{x-1} \equiv b(\text{mod} \ p) \]

的形式,这就是把 \(a\) 提出来的一个过程。这也等价于求 \(a\cdot a^{x-1} + py = b\) 的解。

令 \(d_1 = \gcd(a,p)\)。如果 \(d_1\nmid b\),则原方程无解。

否则由同余的性质得,同余方程就变成

\[\frac{a}{d_1}a^{x-1} \equiv \frac{b}{d_1}(\text{mod} \ \frac{p}{d_1}) \]

这启发我们要不断提取 \(a\) 出来,直到 \(a\) 和模数互质。

设 \(d_2 = \gcd(a,\frac{p}{d_1})\),然后重复上述操作,直到互质。

当 \(a\perp \frac{p}{d_1\dots d_k}\) 时,我们就可以套用 BSGS 了。设 \(D = \prod_{i=1}^kd_i\),原方程就变成了形如

\[\frac{a^k}{D}a^{x-k} \equiv \frac{b}{D}(\text{mod} \ \frac{p}{D}) \]

的形式。因为 \(a\perp \frac{p}{D}\),所以 \(\frac{a^k}{D}\perp \frac{p}{D}\),那么就可以求个逆元,把 \(\frac{a^k}{D}\) 消掉,然后再套一个 BSGS 就可以了。

注意,BSGS 结束后算出来的是 \(x-k\) 而非 \(x\),别忘了把 \(k\) 加上。

实际上,\(\frac{a^k}{D}\) 也可以不用求逆元,只要在 BSGS 枚举 \(i\) 的时候把初值设为 \(\frac{a^k}{D}\) 即可。

code

il int BSGS(int a,int b,int mod,int k)
{
	Hash.clear();
	m = ceil(sqrt(mod));
	Hash[b] = 0 , t = b;
	for(re int i=1;i<m;i++)
	{
		t = 1ll * t * a % mod;
		Hash[t] = i;
	}
	val = ksm(a,m,mod) , t = k;//初值设为k
	for(re int i=1;i<=m;i++)
	{
		t  = 1ll * t * val % mod;
		if(Hash.count(t)) {  return i*m-Hash[t]; }
	}
	return -1;
}

il void exBSGS()
{
	a = read() , mod = read() , b = read();
	if(!a && !mod && !b) exit(0);
	a %= mod , b %= mod;//先模再特判
	if(b == 1 || mod == 1) { puts("0"); return ; }
	cnt = d = 0 , k = 1;
	while((d=gcd(a,mod)) != 1)
	{
		if(b % d) { puts("No Solution"); return; }//无解情况
		cnt++;//不知道为什么这个放在if上面就wa一个点,很怪
		b /= d , mod /= d;//逐渐往下找
		k = 1ll * k * (a / d) % mod;//a^{x-k}前的系数
		if(k == b) { printf("%d\n",cnt); return ; }//k==b说明a^{x-k} = 1,x=k
	}
	ans = BSGS(a,b,mod,k);
	if(ans == -1) puts("No Solution");
	else printf("%d\n",ans+cnt);
}

标签:frac,text,高次,perp,阶和原,BSGS,equiv,同余,mod
From: https://www.cnblogs.com/bloodstalk/p/17436241.html

相关文章

  • 高次方的尾数
    1.问题描述求13的13次方的最后三位数。2.问题分析许多初学者看到本题最容易想到的方法就是:将13累乘13次后截取最后三位即可。但是计算机中存储的整数有一定的范围,超出某范围将不能正确表示,所以用这种算法不可能得到正确的结果。实际上,题目仅要求后三位的值,完全没有必要把13的1......
  • 高次方数尾数
    #define_CRT_SECURE_NO_WARNINGS#include<stdio.h>main(){ intn=13,i; for(i=1;i<=12;i++) { /*n=(n*3+n%100*10)%1000;*/ n=n*13%1000; } printf("%d",n);}......
  • 3.7 高次方数的尾数
    #include<stdio.h>intmain(){inti,x,y,last=1;/★变量last保存求得的×的y次方的部分积的后三位*/printf("Inputxandy:An");scanf("%dSd",&x,&y);for(i-1;i<=y;i++)/*×自乘的次数y*/last=last*x%1000;/*将last乘x后对1000取模,即求积的后三位*/printf(&q......
  • 浅谈同余3(扩展中国剩余定理,扩展BSGS)
    距离上一篇已经四个月了,我来填坑了上一篇:$浅谈同余2(扩展欧几里得,中国剩余定理,BSGS)$(https://www.cnblogs.com/xyy-yyds/p/17418472.html)0x50扩展BSGS$O(\sqrtn)$【模板】扩展BSGS/exBSGS 题目背景题目来源:SPOJ3105Mod题目描述给定$a,p,b$,求满足$a^x≡b\pmodp......
  • 浅谈同余1(常用定理和乘法逆元)
    点个赞吧,球球了~下一篇:$浅谈同余2(扩展欧几里得,中国剩余定理,BSGS)$https://www.acwing.com/file_system/file/content/whole/index/content/7882318/ $\LaTeX$太多了,分成几个部分0x00总写(瞎说)同余是数学中非常重要的东西,这里会写出同余的基本运用若$a\bmodm=b\bmo......
  • [基础数论]同余方程笔记
    前言在学习本节内容前,请确保已完成了二元不定方程的学习。同余方程有无解的判别对于一个方程形如:\[ax\equivb\pmodm\]其中\[a,b\in\mathbbZ,m\in\mathbbZ^+\]并令\[d=(a,m)\]若\(d\nmidb\),则方程\(ax\equivb\pmodm\)无解。若\(d\midb\),......
  • 同余的基本性质
    同余的基本性质注:这里默认$a,b,c,d\in\mathbb{Z},m,k,d\in\mathbb{Z}^+$若$a_1\equivb_1\pmodm$,\(a_2\equivb_2\pmodm\),则\(a_1\pma_2\equivb_1\pmb_2\pmodm\).若$a_1\equivb_1\pmodm$,\(a_2\equivb_2\pm......
  • 同余类与剩余系
    来自潘承洞、潘承彪《初等数论》,有删改。定义1(同余类)把全体整数分为若干个两两不相交的集合,使得\((i)\)在同一个集合中的任两个数模\(m\)一定同余;\((ii)\)在两个不同集合中的任两个数模\(m\)一定不同余。每一个这样的集合称为模\(m\)的同余类。我们以\(r\bmodm\)......
  • 同余的定义以及基本性质学习笔记
    来自潘承洞、潘承彪《初等数论》,有删改。一、定义定义1(同余)设\(m\ne0\)。若\(m\mida-b\),即\(a-b=km\),则称\(m\)为模,\(a\)同余于\(b\)模\(m\)以及\(b\)是\(a\)对模\(m\)的剩余,记作\[a\equivb\pmodm(1)\]否则,则称\(a\)不同余于\(b\)模\(m\),\(b\)不......
  • 高次方的尾数
    自然语言解决问题:许多初学者看到本题最容易想到的方法就是:将13累乘13次后截取最后位即可。但是计算机中存储的整数有一定的范围,超出某范围将不能正确表示,所以用这种算法不可能得到正确的结果。实际上,题目仅要求后三位的值,完全没有必要把13的13次方完全求出来流程图: ......