Baby Steps-Varsity

Giant Step-Astronauts(May'n・椎名慶治)

阅读时可以听听这两首歌,加深对这个算法的理解。(Baby steps少女时代翻唱过,这个原唱反而不是很有名……Giant Step就比较碉,是一个假面骑士片的插曲,由超碉的May'n和一个人建立的临时组合唱的,怕不怕)

这个主要是用来解决这个题:

A^x=B(mod C)(C是质数),都是整数,已知A、B、C求x。

我在网上看了好多介绍,觉得他们写得都不够碉,我看不懂…于是我也来写一发。

先把x=i*m+j,其中m=ceil(sqrt(C)),(ceil是向上取整)。

这样原式就变为A^(i*m+j)=B(mod C),

再变为A^j=B*A^(-m*i) (mod C)

先循环j=0~(C-1),把(A^j,j)加入hash表中,这个就是Baby Steps(现在可以播放Baby Steps-Varsity了)。

下面我们要做的是枚举等号右边,从hash表中找看看有没有,有的话就得到了一组i j,x=i*m+j,得到的这个就是正确解。

所以,接下来要解决的就是枚举B*A^(-m*i) (mod C)这一步(这就是Giant Step,快放Giant Step-Astronauts(May'n・椎名慶治))。

A^(-m*i)相当于1/(A^(m*i)),里面有除法,在mod里不能直接用除法,这时候我们就要求逆元

/*百度百科:

若ax≡1 mod f, 则称a关于模f的乘法逆元为x。也可表示为ax≡1(mod f)。
当a与f互素时,a关于模f的乘法逆元有唯一解。如果不互素,则无解。如果f为素数,则从1到f-1的任意数都与f互素,即在1到f-1之间都恰好有一个关于模f的乘法逆元。
*/
 
然后我们用超碉的exgcd求逆元,exgcd(扩展欧几里德算法)就是在求AB的最大公约数z的同时,求出整数x和y,使xA+yB=z。算法实现就是gcd加几个语句。
然后我们再来看一下exgcd怎么求逆元:

对xA+yB=z,

变成这样xA = z - yB,取B=C(C就是我们要mod的那个)

推导出 xA % C = z %C

只要  z%C==1 时,就可以求出A的逆元x

但用exgcd求完,x可能是负数,还需要这样一下:x=(x%C+C)%C

//--exgcd介绍完毕--

再看我们的题目,

exgcd(A^(m*i) , C)=z,当C是质数的时候z肯定为1,这样exgcd求得的x就是逆元了。

因为x就是A^(m*i)的逆元,P/(A^(m*i))=P*x,所以

B*A^(-m*i) = B/(A^(m*i)) = B*x(mod C)

这样我们的式子A^j=B*A^(-m*i) (mod C)的等号右边就有了,就是B*x,就问你怕不怕!

枚举i,求出右边在hash里找,找到了就返回,无敌!

例题:

http://poj.org/problem?id=2417

代码:

 #include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
using namespace std;
#define ll __int64
#define usint unsigned int
#define RE freopen("1.in","r",stdin) class hash {
public:
hash() {
memset(a,0xff,sizeof(a));
}
int locate(ll x) {
ll l=x%MOD;
while(a[l]!=x&&a[l]!=-) l=(l+)%MOD;
return l;
}
void insert(ll x,ll va) {
ll l=locate(x);
if(a[l]==-) {
a[l]=x;
v[l]=va;
}
}
ll get(ll x) {
ll l=locate(x);
return a[l]==x?v[l]:-;
}
void clear() {
memset(a,0xff,sizeof(a));
}
private:
static const ll MOD=;
ll a[MOD+],v[MOD+];
} S; ll exgcd(ll a,ll b,ll &x,ll &y) {
ll t,ret;
if (!b) {
x=,y=;
return a;
}
ret=exgcd(b,a%b,x,y);
t=x,x=y,y=t-a/b*y;
return ret;
} int main() {///A^x=B(modC) A^j=B*A^(-m*i)(mod C)
ll C,A,B;
ll m,i,t,D,ans,x,y;
while(scanf("%lld%lld%lld",&C,&A,&B)!=EOF) {
S.clear();
m=ceil(sqrt((double)C));
t=;
for(i=; i<m; i++) { /**One, two, baby steps.Three, four, baby steps.Five, six, baby steps.**/
S.insert(t,i);
t=t*A%C;
}
D=;///此时t=A^m
ans=-;
for(i=; i<m; i++) { /**一歩 Giant Step , 君にとってLittle だとしても**/
exgcd(D,C,x,y);///exgcd求逆元,得到x=D^(-i*m)
x=((x*B)%C+C)%C;///B*x=B*D^(-i*m)
y=S.get(x);
//printf("%lld,%lld\n",x,y);
if(y!=-) {
ans=i*m+y;
break;
}
D=(D*t)%C;///D=t^i,(t=A^m)
}
if(ans==-) printf("no solution\n");
else printf("%lld\n",ans);
}
return ;
}

BSGS算法_Baby steps giant steps算法(无扩展)详解的更多相关文章

  1. BSGS(Baby Steps,Giant Steps)算法详解

    BSGS(Baby Steps,Giant Steps)算法详解 简介: 此算法用于求解 Ax≡B(mod C): 由费马小定理可知: x可以在O(C)的时间内求解:  在x=c之后又会循环: 而BS ...

  2. bsgs(Baby Steps Giant Steps)算法

    BSGS算法(Baby Steps Giant Steps算法,大步小步算法,北上广深算法,拔山盖世算法) 适用问题 对于式子: $$x^y=z(mod_p)$$ 已知x,z,p,p为质数: 求解一个 ...

  3. BM算法  Boyer-Moore高质量实现代码详解与算法详解

    Boyer-Moore高质量实现代码详解与算法详解 鉴于我见到对算法本身分析非常透彻的文章以及实现的非常精巧的文章,所以就转载了,本文的贡献在于将两者结合起来,方便大家了解代码实现! 算法详解转自:h ...

  4. BSGS_Baby steps giant steps算法

    BSGS这个主要是用来解决这个题: A^x=B(mod C)(C是质数),都是整数,已知A.B.C求x. 在具体的题目中,C一般是所有可能事件的总数. 解: 设m = ceil(sqrt(C))(ce ...

  5. NOI / 2.5基本算法之搜索-6044:鸣人和佐助详解

    总时间限制: 1000ms 内存限制: 65536kB 题目 佐助被大蛇丸诱骗走了,鸣人在多少时间内能追上他呢? 已知一张地图(以二维矩阵的形式表示)以及佐助和鸣人的位置.地图上的每个位置都可以走到, ...

  6. 二分算法题目训练(三)——Anton and Making Potions详解

    codeforces734C——Anton and Making Potions详解 Anton and Making Potions 题目描述(google翻译) 安东正在玩一个非常有趣的电脑游戏, ...

  7. DOM对象控制HTML无素——详解3

    创建元素节点createElement createElement()方法可创建元素节点.此方法可返回一个 Element 对象. 语法: document.createElement(tagName ...

  8. DOM对象控制HTML无素——详解2

    节点属性 在文档对象模型 (DOM) 中,每个节点都是一个对象.DOM 节点有三个重要的属性 : 1. nodeName : 节点的名称 2. nodeValue :节点的值 3. nodeType ...

  9. DOM对象控制HTML无素——详解1

    getElementsByName()方法 返回带有指定名称的节点对象的集合. 语法: document.getElementsByName(name) 与getElementById() 方法不同的 ...

随机推荐

  1. Activiti系列: 如何给内置表单添加字段类型

     对于内置的表单,除了原来支持的几种数据类型(string, long, enum, date, boolean, collection)之外,还可以自定义数据类型,比如增加一个javascript数 ...

  2. Hash中的一些概率计算

    Hash是把锋利的刀子,处理海量数据时经常用到,大家可能经常用hash,但hash的有些特点你是否想过.理解过.我们可以利用我们掌握的概率和期望的知识,来分析Hash中一些有趣的问题,比如: 平均每个 ...

  3. windows7设置java的环境变量

    win7 下配置 java 环境变量   首先,你应该已经安装了 java 的 JDK 了,笔者安装的是:jdk-7u7-windows-x64 接下来主要讲怎么配置 java 的环境变量,也是为了以 ...

  4. 让Dapper+SqlCE支持ntext数据类型和超过4000字符的存储

    使用Dapper和SqlCE进行开发的时候,如果数据库的某字段是采用的ntext数据类型,并且在这个字段存储的数据超过了4000个字符,会报如下的错误: Invalid parameter Size ...

  5. [BZOJ 2656][ZJOI2012]数列(递归+高精度)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2656 分析: 很容易想到递归分治,但遇到奇数时候f[i]=f[i/2]+f[i/2+1 ...

  6. DOM(二)使用DOM

    在了解DOM(文本对象模型)的框架和节点后,最重要的是使用这些节点处理html网页 对于一个DOM节点node,都有一系列的属性和方法可以使用.常用的有下表. 完善:http://www.w3scho ...

  7. 转-JS子窗口创建父窗口操作父窗口

    Javascript弹出子窗口  可以通过多种方式实现,下面介绍几种方法 (1) 通过window对象的open()方法,open()方法将会产生一个新的window窗口对象 其用法为: window ...

  8. 使用Struts2和jQuery EasyUI实现简单CRUD系统(转载汇总)

    使用Struts2和jQuery EasyUI实现简单CRUD系统(一)——从零开始,ajax与Servlet的交互 使用Struts2和jQuery EasyUI实现简单CRUD系统(二)——aja ...

  9. Java编程思想学习(二) 操作符

    1. 对象“赋值”:对一个对象进行操作时,我们真正操作的是对对象的引用.所以倘若“将一个对象赋值给另一个对象”,实际是将“引用”从一个地方复制到另一个地方.(引用于对象之间存在关联,但这种关联可以被改 ...

  10. Request获取信息总结

    Request.ServerVariables("REMOTE_ADDR")          '获取访问IPRequest.ServerVariables("LOCAL ...