/*************************************
---高次同余方程模板BabyStep-GiantStep--- 输入:对于方程A^x=B(mod C),调用BabyStep(A,B,C),(0<=A,B,C<=10^9) 输出:无解放回-1,有解放回最小非负整数x 复杂度:O(C^0.5),只与C有关,与A,B的大小无关
************************************/ typedef long long ll;
#define HASH_N 100007 struct hashnode
{
int next;
ll key;
int j;
}HashLink[ HASH_N ]; int hashpre[ HASH_N ],hashcnt; void hash_insert(ll x,ll key,int j)
{
for(int p=hashpre[x];p!=-;p=HashLink[p].next)
{
if(HashLink[p].key==key) return ;
}
HashLink[ hashcnt ].key = key;
HashLink[ hashcnt ].j = j;
HashLink[ hashcnt ].next = hashpre[x];
hashpre[x] = hashcnt++;
} int hash_get(ll key)
{
ll x=key%HASH_N;
for(int p=hashpre[x];p!=-;p=HashLink[p].next)
{
if( HashLink[p].key == key ) return HashLink[p].j;
}
return -;
} ll gcd(ll a,ll b)
{
if(b==) return a;
return gcd(b,a%b);
} //ax + by = gcd(a,b)
//传入固定值a,b.放回 d=gcd(a,b), x , y
void extendgcd(long long a,long long b,long long &d,long long &x,long long &y)
{
if(b==){d=a;x=;y=;return;}
extendgcd(b,a%b,d,y,x);
y-=x*(a/b);
} //Ax=1(mod M)
//返回x的范围是[0,M-1]
ll GetNi(ll A,ll M)
{
ll rex=,rey=;
ll td=;
extendgcd(A,M,td,rex,rey);
return (rex%M+M)%M;
} //a^b%mod 快速幂
long long Quk_Mul(long long a,long long b,long long mod)
{
long long qsum=;
while(b)
{
if(b&) qsum=(qsum*a)%mod;
b>>=;
a=(a*a)%mod;
}
return qsum;
} //测试x较小的情况,必须!
ll firsttest(ll A,ll B,ll C)
{
ll tmp=;
if(B==) return ;
for(int i=;i<;i++)
{
tmp = (tmp*A)%C;
if(tmp==B) return i;
}
return -;
} //欧拉函数 返回[1,x-1]中与x互素的数的个数,复杂度n^0.5
ll euler(ll x)
{
ll i, res=x;
for (i = ; i < (ll)sqrt(x * 1.0) + ; i++)
if(x%i==)
{
res = res / i * (i - );
while (x % i == ) x /= i;
}
if (x > ) res = res / x * (x - );
return res;
} ll BabyStep(ll A,ll B,ll C)
{
if(==A || ==C) return -;
if(C==) return ;
B = B%C;
ll ans = firsttest(A,B,C);//为了防止x比较小的时候
if(ans != -) return ans;
ll D=;
int c=;
ll d;
while( (d=gcd(A,C)) != )
{
if( B%d != ) return -;//无解的情况
B /= d;
C /= d;
D = D*A/d%C;
c++;
} //得到了 D*A^(x-c)=B (mod C) ,gcd(A,C)=1 , gcd(D,C)=1
ll D_1=GetNi(D,C);//求D的逆元
B = B*D_1%C;
//求A^x=B (mod C),然后返回x+c
ll m = ceil( sqrt(C+0.0) ); memset(hashpre,-,sizeof(hashpre));
hashcnt=;
ll hashnum=;
hash_insert(, , );
for(int i=;i<m;i++)
{
hashnum = (hashnum*A)%C;
hash_insert(hashnum%HASH_N, hashnum ,i);
} ll ol=euler(C);
ll mA=Quk_Mul(A, m, C);
ll ta=; ll tmpni = Quk_Mul(mA, ol-, C); for(int i=;i<m;i++,ta=ta*tmpni%C)
{
//解线性同余方程 tx=B*ta (%C) ,ta直接用费马小定理求逆元
ll tx = ta;
tx = (tx*B)%C;
int j=hash_get(tx);
if(j!=-)//找到解了
{
return i*m+j+c;
}
} return -;
}

其实还是很很正常的解法,这个甚至可以当成一道难一点的数论题目做。

关于详细的解释。

[转自http://blog.csdn.net/auto_ac/article/details/11842695]

题意:求满足a^x=b(mod n)的最小的整数x。

分析:很多地方写到n是素数的时候可以用Baby step,Giant step, 其实研究过Baby step,Giant step算法以后,你会发现  它能解决    “n与a互质”的情况,而并不是单纯的n是素数的情况。如果a与n不是互质的,那么我们需要处理一下原方程,让a与n互质,然后再用Baby step,Giant step解出x即可。

Baby step,Giant step算法思想:对于a与n互质,那么则有a^phi(n)=1(mod n),   对于n是素数phi(n) == n-1, 否则phi(n) < n-1, 所以x的取值只要在0----n-2之中取就可以了。

当n很小时,可以直接枚举,但当n很大时,肯定会超时,Baby step,Giant step就是用了一种O(sqrt(n)*log(n))的方法枚举了所有的0-----n-2。令m = sqrt(n);

我们可以预处理出a^0,a^1,.........a^m,都放入哈希表中, 然后  (a^m)^i+v(哈希表里的其中一个值)就一定是解,每次枚举i(0-----m-1),计算出v,判断v是否出现在哈希表中,如果有就是解。  对于m为什么取sqrt(n)是为了复杂度的平衡,这一点是跟分块算法很相似的。

对于a与n不互质的情况分析:令 t = gcd(a,n),那么a与n都约去t,当然b也要约去t(不能约去就无解),约去一个t以后方程就变为   aa*a^(x-1) = bb(mod nn), (其中  aa = a/t    bb = b/t    nn = n/t) , 这里nn还可能与a不互质,那么我们一直拿出一个新的a对(a, bb, nn)约去t,直到a与nnn....(nnn...表示约去若干次t以后的n)互质。以下用(用三个字母表示约去若干次后,如bbb) 则结果为aa^c*a^(x-c) = bbb(mod nnn),      我们让等式左右分别乘以aa^c关于nnn的逆元       变为a^(x-c) = w    (mod  nnn) ,    w =bbb *(aa^c)^(-1)。   a^x = w  (mod n)可以用bbb *(aa^c)^(-1)Baby step,Giant step直接求出,如果有解那把未知数+c。

具体看代码中的cal函数。

注意:在以上过程中x有可能<c,所以我们必须每约去一个t就要特判一下当前情况aa 与 bb就说明当前c是解。

哈希表实现看题目时间要求,map太慢,自己手写hash是很快的。

高次同余方程模板BabyStep-GiantStep的更多相关文章

  1. 『高次同余方程 Baby Step Giant Step算法』

    高次同余方程 一般来说,高次同余方程分\(a^x \equiv b(mod\ p)\)和\(x^a \equiv b(mod\ p)\)两种,其中后者的难度较大,本片博客仅将介绍第一类方程的解决方法. ...

  2. 数论之高次同余方程(Baby Step Giant Step + 拓展BSGS)

    什么叫高次同余方程?说白了就是解决这样一个问题: A^x=B(mod C),求最小的x值. baby step giant step算法 题目条件:C是素数(事实上,A与C互质就可以.为什么?在BSG ...

  3. ACM_高次同余方程

    /*poj 3243 *解决高次同余方程的应用,已知 X^Y = K mod Z, 及X,Z,K的值,求 Y 的值 */ #include<cstdio> #include<cstr ...

  4. 【解高次同余方程】51nod1038 X^A Mod P

    1038 X^A Mod P 基准时间限制:1 秒 空间限制:131072 KB 分值: 320 X^A mod P = B,其中P为质数.给出P和A B,求< P的所有X. 例如:P = 11 ...

  5. Discrete Log Algorithms :Baby-step giant-step

    离散对数的求解 1.暴力 2.Baby-step giant-step 3.Pollard’s ρ algorithm …… 下面搬运一下Baby-step giant-step 的做法 这是在 ht ...

  6. poj2417(Baby-Step Giant-Step)

    题目链接:http://poj.org/problem?id=2417 题意:求满足给出 P, N, B, 求满足条件 BL == N (mod P) 的最小 L, 若不存在则输出 no soluti ...

  7. Baby-step giant-step算法

    写在前面: 学习笔记,方便复习,学习资料来自网络,注明出处 我们都在努力奔跑,我们都是追梦人 结论 In group theory, a branch of mathematics, the baby ...

  8. 第三十四个知识点:描述攻击离散对数问题的baby-step/Giant-step方法

    第三十四个知识点:描述攻击离散对数问题的baby-step/Giant-step方法 Baby-step/Giant-step是Dnaiel Shanks为解决DLP问题开发的算法.DLP问题已经是许 ...

  9. POJ 3243 Clever Y (求解高次同余方程A^x=B(mod C) Baby Step Giant Step算法)

    不理解Baby Step Giant Step算法,请戳: http://www.cnblogs.com/chenxiwenruo/p/3554885.html #include <iostre ...

随机推荐

  1. 如何评价 GitHub 发布的文本编辑器 Atom?

    这里是HN上的讨论:GitHub's new text editor leaked on Twitter这里是github page:Atom · GitHub 好多repo啊我不知道有没有知友了解更 ...

  2. Java:网络编程之登陆服务器

    1. 客服端:浏览器(telnet) 服务端:自定义 2. 客服端:浏览器 服务端:TomCat服务器 3. 客服端:自定义 服务端:TomCat服务器   //例子如下: import java.n ...

  3. tez参数

    https://tez.apache.org/releases/0.8.4/tez-api-javadocs/configs/TezConfiguration.html

  4. oracle sql试题

    转载 数据准备 create table student(  sno varchar2(10) primary key,  sname varchar2(20),  sage number(3),  ...

  5. Linux取消挂载,删除用户及其目录

    取消挂载 取消挂载命令: umount /dev/sdb 命令umount 文件系统/挂载点 umount /dev/sdb 例如:umount /dev/sdb即可将sdb1取消挂载. 如果出现de ...

  6. 【共享单车】—— React后台管理系统开发手记:AntD Table基础表格

    前言:以下内容基于React全家桶+AntD实战课程的学习实践过程记录.最终成果github地址:https://github.com/66Web/react-antd-manager,欢迎star. ...

  7. Maven够用就好

    学习maven.仅仅要知道pom.dependency.coordination就能够了,剩下的就是学习一个一个的plugin的Goal 配置maven 下载    http://maven.apac ...

  8. Java基础学习过程

    转载:http://blog.csdn.net/scythe666/article/details/51699954JVM 1. 内存模型( 内存分为几部分? 堆溢出.栈溢出原因及实例?线上如何排查? ...

  9. VM虚拟机 Windows虚拟机中linux鼠标不能动怎么办

    有一次vmware安装red hat linux后,进入x-windows界面,鼠标不能用,百思不得其解,因为自己的安装linux的过程中设置绝对是没有问题的啊,鼠标设置肯定是usb带滑轮,这个肯定没 ...

  10. 你真的了解装箱(Boxing)和拆箱(Unboxing)吗?

    所谓装箱就是装箱是将值类型转换为 object 类型或由此值类型实现的任一接口类型的过程.而拆箱就是反过来了.很多人可能都知道这一点,但是是否真的就很了解boxing和unboxing了呢?可以看下下 ...