BSGS

BSGS,全称叫 BabyStepGiantStep,也就是大步小步

其实还是比较暴力的

它可以\(O(\sqrt p)\)的复杂度内解出:

\[a^x\equiv n\pmod p,\gcd(a,p)=1
\]

中\(x\)的值

如果\(\gcd(a,p)\neq 1\)就要用到 exBSGS 了

我们考虑令\(x=im-k,0\le k<m\)

那么原式变为

\[a^{im-k}\equiv n\pmod p
\]

\[a^{im}\equiv na^k\pmod p
\]

那么,我肯可以枚举\(k\in[0,m)\),计算出\(na^k\bmod p\)的值,然后把对应的\(k\)存下来

可以用map或 hash,用map会多一个\(\log\)

然后,再枚举\(i\in[0,\lceil\frac{p}{m}\rceil]\),计算出\(a^{im}\bmod p\)

然后看一看之前有没有一个\(k\),使得\(na^k\equiv a^{im}\pmod p\),且\(im>=k\)

如果有,那么答案肯定就是\(im-k\)

如果一直没找到,那么就无解

复杂度是\(O(\max(m,\frac{p}{m} ))\),显然,让\(m=\lceil \sqrt p \rceil\)时最优,即为\(O(\sqrt p)\)

但是,我们考虑的只是\(x\in[1,p]\)的情况,那为什么要找的这个\(x\)一定满足这样的性质呢?

首先\(\gcd(a,p)=1\),满足欧拉定理的条件,也就是会有\(a^{\varphi(p)}\equiv 1\pmod p\Rightarrow a^{q\varphi(p)}\equiv 1\pmod p,q\in\mathbb{N^*}\)

那么,\(k\bmod \varphi(p)=k-q\varphi(p)<\varphi(p)<p\)

则\(a^{k\bmod \varphi(p)}=\dfrac{a^k}{a^{q\varphi(p)}}\)

又由于那个分母在\(\bmod p\)中同余于\(1\)

所以\(a^{k\bmod \varphi(p)}\equiv a^k\pmod p\)

则可以得知,要求的最小的\(x\),如果有解,一定满足\(x<\varphi(p)<p\)

模板题:P3846 [TJOI2007] 可爱的质数

这题保证了\(a,n<p\),所以不需要一些奇奇怪怪的特判

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<iomanip>
#include<cstring>
#include<map>
#define reg register
#define EN std::puts("")
#define LL long long
inline int read(){
register int x=0;register int y=1;
register char c=std::getchar();
while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
return y?x:-x;
}
std::map<int,int>map;
inline int power(int a,int b,int p){
int ret=1;
while(b){
if(b&1) ret=1ll*ret*a%p;
b>>=1;a=1ll*a*a%p;
}
return ret;
}
inline int BSGS(int a,int n,int p){
reg int m=std::ceil(std::sqrt(p));
for(reg int i=0,s=n;i<m;i++,s=1ll*s*a%p) map[s]=i;
for(reg int i=0,tmp=power(a,m,p),s=1;i<=m;i++,s=1ll*s*tmp%p)
if(map.find(s)!=map.end())
if(i*m>=map[s]) return i*m-map[s];
return -1;
}
int main(){
int p=read(),a=read(),n=read();
LL ans=BSGS(a,n,p);
ans==-1?std::puts("no solution"):std::printf("%lld",ans);
return 0;
}

exBSGS

用于处理上面哪个问题\(\gcd(a,p)\neq 1\)的情况

有些细节稍显恶心(其实还好

首先,原来那个同余方程可以等价的写成:

\[a^x+kp=n
\]

设\(\gcd(a,p)=d\)

由于斐蜀定理,这个式子有解的充要条件是\(d\mid n\),否则直接返回无解

那么上面的式子就是:

\[a^{x-1}\cdot \frac{a}{d}+k\cdot\frac{p}{d}=\frac{n}{d}
\]

此时,\(a^{x-1}\rightarrow a^x,\frac{p}{d}\rightarrow p,\frac{n}{d}\rightarrow n\)

那么一直递归,直到\(\gcd(a,p)=1\)

所以此时设一共递归了\(cnt\)次,这所有次递归的\(d\)的乘积是\(d\)(用一个字母说起来省事

原式就是

\[a^{x-cnt}\cdot \frac{a^{cnt}}{d}\equiv \frac{n}{d}\pmod {\frac{p}{d}}
\]

那么我们就用\(a'=a,n'=\frac{n}{d},p'=\frac{p}{d}\)来跑一次 BSGS 就行了

当然,答案还要再加上\(cnt\)

而且,还有一个\(\dfrac{a^{cnt}}{d}\)的系数要乘上,具体对应代码中的变量ad,要传参到 BSGS 的函数里

模板题:SP3105 MOD - Power Modulo InvertedP4195 【模板】exBSGS

还是双倍经验,但是这个不保证\(a,n<p\),所以要先模一下,然后判断一下是不是等于\(0\),具体看代码

而且这个还卡常,必须要用unordered_map,它的内部实现是哈希表,而map是红黑树,前者构建好像稍慢,但是查询快,适合这个题

话说我写这题的时候听说卡常,然后T了以后猛卡常数,结果后来发现是写法错了,于是就对着错误的程序卡了一晚上常直至自闭

不过是 c++11 的东西,noip可能不能用,编译时要加上-std=c++11

当然写 hash 也可以,但我不太会/kk

#include<cstdio>
#include<map>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<iomanip>
#include<cstring>
#include<unordered_map>
#define reg register
#define EN std::puts("")
#define LL long long
inline int read(){
register int x=0;register int y=1;
register char c=std::getchar();
while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
return y?x:-x;
}
std::unordered_map<int,int>map;
int gcd(int a,int b){return b?gcd(b,a%b):a;}
inline int BSGS(int a,int n,int p,int ad){
map.clear();
reg int m=std::ceil(std::sqrt(p));
reg int s=1;
for(reg int i=0;i<m;i++,s=1ll*s*a%p) map[1ll*s*n%p]=i;
for(reg int i=0,tmp=s,s=ad;i<=m;i++,s=1ll*s*tmp%p)
if(map.find(s)!=map.end())
if(1ll*i*m-map[s]>=0) return 1ll*i*m-map[s];
return -1;
}
inline int exBSGS(int a,int n,int p){
a%=p;n%=p;
if(n==1||p==1) return 0;
reg int cnt=0;
reg int d,ad=1;
while((d=gcd(a,p))^1){
if(n%d) return -1;
cnt++;n/=d;p/=d;
ad=(1ll*ad*a/d)%p;
if(ad==n) return cnt;
}
// std::printf("a: %d n: %d p: %d ad:%d\n",a,n,p,ad);
LL ans=BSGS(a,n,p,ad);
if(ans==-1) return -1;
return ans+cnt;
}
signed main(){
int a=read(),p=read(),n=read();
while(a||p||n){
int ans=exBSGS(a,n,p);
if(~ans) std::printf("%d\n",ans);
else std::puts("No Solution");
a=read();p=read();n=read();
}
return 0;
}

最新文章

  1. 小白挑战:AsyncTask源码分析
  2. ccf模板生成
  3. pylab模式
  4. mysql修改字段的语句写法
  5. 开启Mysql慢查询来优化mysql
  6. Unable to boot : please use a kernel appropriate for your cpu
  7. Cocos2d-X中间应用
  8. hdu1037
  9. hibernate框架学习笔记1:搭建与测试
  10. 排序算法入门之快速排序(java实现)
  11. (转)SQLServer_十步优化SQL Server中的数据访问五
  12. 远程连接ORACLE服务
  13. 从错误0x80070522,谈强制完整性控制(MIC)。
  14. Oracle登录后提示ORA-12154:TNS:无法解析指定的连接标识符
  15. [C#.Net]判断文件是否被占用的两种方法
  16. 查询结果用Object类或其数组的List接收
  17. 结对测试 vs 随机测试
  18. Linux实战教学笔记22:企业级NFS网络文件共享服务
  19. eclipse的debug模式经常自动跳到TheadPoolExecutor的断点
  20. 对PHP中类、继承、抽象的理解(个人总结)

热门文章

  1. javascript入门 之 ztree(三 简单json数据)
  2. python3(二十) module
  3. python3(十二)functional
  4. bootstrapTest
  5. 差分数组&amp;&amp;定义&amp;&amp;使用方法&amp;&amp;与线段树的区别
  6. 小说免费看!python爬虫框架scrapy 爬取纵横网
  7. 详解 Map集合
  8. SpringBoot集成Shiro实现权限控制
  9. CISCN love_math和roarctf的easy_clac学习分析
  10. ios快捷指令编程尝试