上一篇博文中说道了baby step giant step的方法(简称BSGS),不过对于XY mod Z = K ,若x和z并不互质,则不能直接套用BSGS的方法了。

  为什么?因为这时候不存在逆元了啊,那么怎么办呢?

  既然是x和z不互质,那么我们就想办法让他们互质,再套用BSGS的解法即可。(这就是所谓的消因子法)

代码如下:

 #include<cstdio>
#include<cstring>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
#define LL long long
#define Maxn 40000 LL x,z,k,aa,m;
int cnt,num;
int ok; struct node
{
int idx;LL val;
}baby[Maxn]; LL ax,ay;
LL exgcd(LL a,LL b)
{
if(b==) {ax=,ay=;return a;}
LL g=exgcd(b,a%b);
LL yy=ay;
ay=ax-a/b*ay;ax=yy;
return g;
} bool cmp(node x,node y) {return x.val==y.val?x.idx<y.idx:x.val<y.val;} int ffind(LL x)
{
int head=,tail=cnt;
while(head<tail)
{
int mid=(head+tail)>>;
if(baby[mid].val==x) return baby[mid].idx;
if(baby[mid].val>x) tail=mid-;
else head=mid+;
}
if(baby[head].val==x) return baby[head].idx;
return -;
} bool init()
{
scanf("%lld%lld%lld",&x,&z,&k);
//if(==EOF) return 0;
if(x==&&z==&&k==) return ;k%=z;
LL g,bm;
bm=%z;aa=,num=;ok=;
//if(k>=z) {ok=0;return 1;}
for(int i=;i<=;i++) if(bm==k) {printf("%d\n",i);ok=;return ;}
else bm=(bm*x)%z;
while((g=exgcd(x,z))!=)
{
aa=(aa*x/g)%z,z/=g;num++;
if(k%g!=) {ok=-;break;}
k/=g;
}
return ;
} LL BSGS()
{
baby[].idx=,baby[].val=aa%z;
m=(LL)(ceil(double(sqrt((double)z))));
for(int i=;i<=m;i++) baby[i].idx=i,baby[i].val=(baby[i-].val*x)%z;
LL bm=%z,ans=-,g;
for(int i=;i<=m;i++) bm=(bm*x)%z;
g=exgcd(bm,z);
bm=ax/g; bm=(bm%(z/g)+(z/g))%(z/g);
if(bm==) bm=z/g;
sort(baby,baby+m+,cmp);cnt=;
for(int i=;i<=m;i++) if(baby[i].val!=baby[cnt].val) baby[++cnt]=baby[i];
LL tmp=k;
for(int i=;i<=m;i++)
{
int j;
if((j=ffind(tmp))!=-)
{
ans=i*m+j;
break;
}
tmp=(tmp*bm)%z;
}
return ans;
} int main()
{
while()
{
LL ans;
if(!init()) break;
if(ok==) continue;
else if(ok==-) printf("No Solution\n");
else
{
ans=BSGS();
if(ans==-) printf("No Solution\n");
else printf("%lld\n",ans+num);
}
}
return ;
}

poj3243 (二分版)

  另外,find部分可以不用二分,而用hash解决。感觉大部分情况下还是hash比较快,但是比较耗空间。

  把你需要存的数,即x的0~m次方算出来,假设是t,我们设m=1<<16-1,然后用t异或^m得nt(就是取t二进制后的15位进行hash),然后存到hash表里面去。如果t的位置目前没有存数,那么我们就直接存到hash[t]上去,如果t位置已经存了数(因为后15位为t的可能有多种情况),我们就在len除增加一个位置,把nt存到那里面去,然后hash[t].next=len,把位置记录下来,这应该就相当于一条链了。查找的时候循着这条链找下去即可,链的尽头的next用-1标记。

  hash版代码如下:

 #include<cstdio>
#include<cstring>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
#define LL long long
#define Maxn 40000
const int pp=(<<)-; LL x,z,k,aa,m;
int cnt,num;
int ok; struct node
{
int idx,nt;
LL val;
}baby[*Maxn];int len; LL ax,ay;
LL exgcd(LL a,LL b)
{
if(b==) {ax=,ay=;return a;}
LL g=exgcd(b,a%b);
LL yy=ay;
ay=ax-a/b*ay;ax=yy;
return g;
} void ins(LL now,int id)
{
int x=now&pp;
if(baby[x].idx==-) {baby[x].idx=id;baby[x].val=now;return;}
while(baby[x].val!=now&&baby[x].nt!=-) x=baby[x].nt;
if(baby[x].val==now) return;
baby[x].nt=++len;
baby[len].nt=-;baby[len].val=now;baby[len].idx=id;
} bool init()
{
scanf("%lld%lld%lld",&x,&z,&k); if(x==&&z==&&k==) return ;k%=z;
LL g,bm;
bm=%z;aa=,num=;ok=; for(int i=;i<=;i++) if(bm==k) {printf("%d\n",i);ok=;return ;}
else bm=(bm*x)%z;
while((g=exgcd(x,z))!=)
{
z/=g,aa=(aa*x/g)%z;num++;
if(k%g!=) {ok=-;break;}
k/=g;
} return ;
} int ffind(LL now)
{
int x=now&pp;
if(baby[x].idx==-) return -;
while(baby[x].val!=now&&baby[x].nt!=-) x=baby[x].nt;
if(baby[x].val!=now) return -;
return baby[x].idx;
} LL BSGS()
{
m=(LL)(ceil(double(sqrt((double)z)))); for(int i=;i<=pp;i++) baby[i].idx=baby[i].nt=-; LL now=aa%z; len=pp;
for(int i=;i<=m;i++) {ins(now,i);now=(now*x)%z;} LL bm=%z,ans=-;
for(int i=;i<=m;i++) bm=(bm*x)%z;
LL g=exgcd(bm,z);
bm=ax/g; bm=(bm%(z/g)+(z/g))%(z/g);
if(bm==) bm=z/g; LL tmp=k;
for(int i=;i<=m;i++)
{
int j;
if((j=ffind(tmp))!=-)
{
ans=i*m+j;
break;
}
tmp=(tmp*bm)%z;
}
return ans;
} int main()
{
while()
{
LL ans;
if(!init()) break;
if(ok==) continue;
else if(ok==-) printf("No Solution\n");
else
{
ans=BSGS();
if(ans==-) printf("No Solution\n");
else printf("%lld\n",ans+num);
}
}
return ;
}

poj3243 (hash版)

  在我的理解中呢,hash相当于给每个数给予一个特征,这个特征的种类有限,而且我们根据一个数可以很快知道他的特征。我们存数的事后呢,就把相同特征的存到一起。查找的时候呢,循着这个特征找,就可以很快地找到这个数了。这个特征也要定好,使得随机的数据里面用有着相同特征的个数尽量少。

2016-02-04 09:14:28

-----------------------------------------

2016-08-27 11:29:01 更新

【POJ3243】拓展BSGS(附hash版)的更多相关文章

  1. 【POJ 3243】Clever Y 拓展BSGS

    调了一周,我真制杖,,, 各种初始化没有设为1,,,我当时到底在想什么??? 拓展BSGS,这是zky学长讲课的课件截屏: 是不是简单易懂.PS:聪哥说“拓展BSGS是偏题,省选不会考,信我没错”,那 ...

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

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

  3. 【SPOJ】Power Modulo Inverted(拓展BSGS)

    [SPOJ]Power Modulo Inverted(拓展BSGS) 题面 洛谷 求最小的\(y\) 满足 \[k\equiv x^y(mod\ z)\] 题解 拓展\(BSGS\)模板题 #inc ...

  4. 数学:拓展BSGS

    当C不是素数的时候,之前介绍的BSGS就行不通了,需要用到拓展BSGS算法 方法转自https://blog.csdn.net/zzkksunboy/article/details/73162229 ...

  5. python实现文章或博客的自动摘要(附java版开源项目)

    python实现文章或博客的自动摘要(附java版开源项目) 写博客的时候,都习惯给文章加入一个简介.现在可以自动完成了!TF-IDF与余弦相似性的应用(三):自动摘要 - 阮一峰的网络日志http: ...

  6. [拓展Bsgs] Clever - Y

    题目链接 Clever - Y 题意 有同余方程 \(X^Y \equiv K\ (mod\ Z)\),给定\(X\),\(Z\),\(K\),求\(Y\). 解法 如题,是拓展 \(Bsgs\) 板 ...

  7. 【POJ3243】【拓展BSGS】Clever Y

    Description Little Y finds there is a very interesting formula in mathematics: XY mod Z = K Given X, ...

  8. 【HDU2815】【拓展BSGS】Mod Tree

    Problem Description   The picture indicates a tree, every node has 2 children.  The depth of the nod ...

  9. POJ 3243 Clever Y | BSGS算法完全版

    题目: 给你A,B,K 求最小的x满足Ax=B (mod K) 题解: 如果A,C互质请参考上一篇博客 将 Ax≡B(mod C) 看作是Ax+Cy=B方便叙述与处理. 我们将方程一直除去A,C的最大 ...

随机推荐

  1. RHEL(RedHat Enterprise Linux)5/6 ISO镜像下载

    本文贴出了RHEL(RedHat Enterprise Linux)发行版本中常用的服务器版本的ISO镜像文件,供大家下载学习使用,贴出的版本有RedHat Enterprise Linux(RHEL ...

  2. C# 条码标签打印程序,RDLC报表动态显示多条码标签的方法

    初学c#,因最近公司客户要求原出货标签需实现条码化,练手的机会来了,遂动手做这个程序,开始都是一些增删改查操作一直很顺利,但到RDLC报表将条码显示到报表上犯难了,因为初学未接触过报表,上网查资料均一 ...

  3. Java基础(二)

    下面来实现一个小程序,要求如下: 从键盘接收一个字符串,程序对其中所有的字符进行排序,例如键盘输入:helloitcast程序打印acehillostt 步骤分析: 1.键盘录入字符串,Scanner ...

  4. Optimize str2date function

    The job can be any string date format convert to AX date format. so that, Do not need to specify str ...

  5. Spark菜鸟学习营Day4 单元测试程序的编写

    Spark菜鸟学习营Day4 单元测试程序的编写 Spark相比于传统代码是比较难以调试的,单元测试的编写是非常必要的. Step0:需求分析 在测试案例编写前,需完成需求分析工作,明确程序所有的输入 ...

  6. 表达式语言之java对正则表达式的处理

    正则表达式用于字符串匹配,字符串查找,字符串替换等.例如注册email格式的验证等.java中处理正则表达式相关的类主要有java.lang.String,java.util.regex.Patter ...

  7. Oracle之存储过程

    1.存储过程创建 oracle中创建存储过程的语法如下: CREATE [OR REPLACE] PROCEDURE PRO_NAME[(parameter1[,parameter2]...)]is| ...

  8. Objective-C的内省(Introspection)小结

    内省(Introspection)是面向对象语言和环境的一个强大特性,Objective-C和Cocoa在这个方面尤其的丰富.内省是对象揭示自己作为一个运行时对象的详细信息的一种能力.这些详细信息包括 ...

  9. php用户注册

    前言 网站用户注册与登录是很常用的一个功能,本节教材就以此来演示一下 PHP 中如何开发用户注册与登录模块. 本节需要用到的重点 PHP 基础知识: PHP 中预定义 $_POST 和 $_GET 全 ...

  10. Ffmpeg 定位文件(seek file)

    有朋友问到ffmpeg播放文件如何定位问题,我想到应该还有一些新手朋友对这一块比较陌生.ffmpeg定位问题用到seek方法,代码 如下: void SeekFrame(AVFormatContext ...