ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

BSGS

2020-07-25 17:01:59  阅读:279  来源: 互联网

标签:int void BSGS equiv include mod


BSGS

前置芝士

\(Baby-Step-Giant-Step\) 算法,即大步小布算法,缩写为 \(BSGS\)

作用

解决类似 \(y^x\equiv z(mod~p)\),给定 \(y,z,p>=1\) 求解 \(x\) 的问题

(普通的 \(BSGS\) 只能求解 \(gcd(y,p)=1\) 的情况)

推导过程

设 \(x=a*m+b,m=\lceil \sqrt p \rceil,a\in[0,m),b\in[0,m)\)

则 \(y^{a*m}\equiv z*y^{-b}(mod~p)\)

怎么求解?(当然可以逆元,主要是懒)

为了方便,设 \(x=a∗m−b\) ,那么\(y^{a*m}\equiv z∗y^b(mod~p)\)

枚举 \(b\in[0,m]\) ,将 \(z*y^b\) 存入 \(hash\) 表(也可存入 \(map\) ,但是常数较大,没有 \(hash\) 跑的快)

枚举 \(a\in[1,m]\) ,从 \(hash\) 表中寻找第一个满足 \(y^{a*m}\equiv z∗y^b(mod p)\)

此时 \(x=a*m-b\) 即为所求 (这里面 \(m=\sqrt p\) )

(接下来是短暂的证明 \(m\) 为什么取 \(\sqrt p\))

\(x\) 值最大时 \(a=m,b=0\) ,为 \(x=m*m=p\) ,超过 \(p\) 怎么办?

有一个公式 \(a^{p-1}\equiv 1(mod~p)\) 因此 \(a^k\equiv\dfrac{a^k}{a^{(p-1)*w}}(mod~p)\)

当 \(k>p\)时,可化为 \(a^k\equiv a^{(k~mod~p-1)}(mod~p)\)

所以 \(x>p\) 也会被%到 \(x<p\) ,这时可以直接找之前的答案

例题

P2485 [SDOI2011]计算器

题意

健达计算器,三个操作,一次满足(不是

思路

第一种:快速幂即可。

第二种:用拓展欧几里得算法即可。已知 \(a,b,p\) ,求 \(x\) 的最小值,使得 \(a*x\equiv b(mod~p)\) ,

​ 可转化为:\(a*x+p*y=b\) ,要求 \(gcd(a,p)|b\) ,否则无解。

​ (鄙人偷懒,用了另一种办法:\(xy=z(mod~p)~~=>~~x\equiv z*y^{-1}(mod~p)\) ,

​ 然后用乘法逆元求解即可)

第三种: \(BSGS\) 即可。

(记得特判 \(y|p\) 的情况)

代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<map>
#include<cmath>
#include<vector>
#include<set>
#define ll long long
#define re register

using namespace std;
const int HashMod=100007;

inline int read(){
	re int x=0,f=1;
	re char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)) {x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return x*f;
}

int fpow(int a,int b,int mod)
{
	int s=1;
	while(b){
		if(b&1)
			s=1ll*s*a%mod;
			a=1ll*a*a%mod;
			b>>=1;
	}
	return s;
}

namespace Task1
{
	void Solve(int y,int z,int p){
		printf("%d\n",fpow(y,z,p));}
}

namespace Task2
{
	void Solve(int y,int z,int p){
		if(y%p==0&&z%p)
			puts("Orz, I cannot find x!");
		else
			printf("%lld\n",1ll*fpow(y,p-2,p)*z%p);//就是这里,因为写了快速幂,就顺手用了一下  
	}
}

namespace Task3
{
	struct HashTable//hash表  
	{
		struct Line{ int u,v,next;}e[1000000];
		int h[HashMod],cnt;
		void add(int u,int v,int w)
		{
			e[++cnt]=(Line){w,v,h[u]};h[u]=cnt;
		}
		void Clear(){memset(h,0,sizeof(h));cnt=0;}
		void Hash(int x,int k){
			int s=x%HashMod;
			add(s,k,x);
		}
		int query(int x){
			int s=x%HashMod;
			for(re int i=h[s];i;i=e[i].next)
				if(e[i].u==x) return e[i].v;
			return -1;
		}
	}Hash;
	void Solve(int y,int z,int p){
		if(y%p==0){
			puts("Orz, I cannot find x!");
			return ;
		}
		y%=p;z%=p;
		if(z==1) {
			puts("0");
			return ;
		}
		int m=sqrt(p)+1;Hash.Clear();//注意 m 要向上取整 
		for(re int i=0,t=z;i<m;i++,t=1ll*t*y%p) Hash.Hash(t,i);//枚举x=a*m-b中的b  
		for(re int a=1,tt=fpow(y,m,p),t=tt;a<=m;a++,t=1ll*t*tt%p)//枚举x=a*m-b中的a  
		{
			int b=Hash.query(t);
			if(b==-1) continue;
			printf("%d\n",a*m-b);
			return ;
		}
		puts("Orz, I cannot find x!");
	}
}

int main(){
	int T=read(),K=read();
	while(T--)
	{
		int y=read(),z=read(),p=read();
		if(K==1) Task1::Solve(y,z,p);
		if(K==2) Task2::Solve(y,z,p);
		if(K==3) Task3::Solve(y,z,p);
	}
	return 0;
}

这个就自己做吧,比例题还简单)

至于 \(ex~BSGS\) 就在下一篇博客了

标签:int,void,BSGS,equiv,include,mod
来源: https://www.cnblogs.com/jasony/p/13377315.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有