zoukankan      html  css  js  c++  java
  • BSGS

    用途:求( a^x equiv b (mod p) 中的x )

    一、对于p为质数的情况

    此时 ( 0 leq x leq p-1 )

    设 ( m=left lceil sqrt{p} ight ceil ,x=i*m-j )这里-的作用是避免逆元

    于是可以把式子变形成这样: ( a^{im}equiv ba^j(mod p) )

    枚举右边 ( 0 leq j <m ),用map或者hash以模数为下标来存每一个j

    枚举左边( 0 leq i <m ) ,在map或者hash中查找对应的模数

    二、对于gcd(a,p)==1的情况

    此时 ( 0 leq x leq varphi(p) )

    其余同上

    三、对于gcd(a,p)>1的情况

    即扩展BSGS

    把式子变成等式的形式:( a^x+yp=b )

    设( g=gcd(a,p) )

    那么两边同时除以g就会变成:( frac{a}{g} a^{x-1}+yfrac{p}{g}=frac{b}{g} )

    如此循环到情况二,然后正常求即可

    最后答案加上循环次数,即当前的x是经过几次减一得到的

    注意有很多关于0和1的特判

    扩展BSGS模板:

    //map
    #include<iostream>
    #include<cstdio>
    #include<map>
    #include<cmath>
    using namespace std;
    int a,b,p,ans;
    map<int,int>mp;
    int gcd(int a,int b)
    {
    	return b==0?a:gcd(b,a%b);
    }
    int ksm(int a,int b,int p)
    {
    	int r=1;
    	while(b)
    	{
    		if(b&1)
    			r=(long long)r*a%p;
    		a=(long long)a*a%p;
    		b>>=1;
    	}
    	return r;
    }
    int BSGS(int a,int b,int p)
    {
    	a%=p,b%=p;
    	if(b==1)
    		return 0;
    	int cnt=0,d=1;
    	for(int g=gcd(a,p);g!=1;g=gcd(a,p))
    	{
    		if(b%g)
    			return -1;
    		p/=g,b/=g;
    		d=(long long)d*a/g%p;
    		cnt++;
    		if(b==d)
    			return cnt;
    	}
    	mp.clear();
    	int m=ceil(sqrt(p)),t=b;
    	for(int i=0;i<m;i++)
    	{
    		mp[t]=i;
    		t=(long long)t*a%p;
    	}
    	int g=ksm(a,m,p);
    	t=(long long)d*g%p;
    	for(int i=1;i<=m+1;i++)
    	{
    		if(mp[t])
    			return cnt+i*m-mp[t];
    		t=(long long)t*g%p;
    	}
    	return -1;
    } 
    int main()
    {
    	while(scanf("%d%d%d",&a,&p,&b)&&a+b+p)
    	{
    		if(p==1)
    		{
    			puts("0");
    			continue;
    		}
    		ans=BSGS(a,b,p);
    		if(ans==-1)
    			puts("No Solution");
            else 
    			printf("%d
    ",ans);
    	}
    	return 0;
    }
    //hash
    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    using namespace std;
    const int mod=739391,N=2e6;
    int a,b,p,ans,ti,v[N],con;
    struct qwe
    {
    	int b,v,ne;
    }ha[N];
    void ins(int w,int b,int va)
    {//cout<<va<<endl;
    	if(v[w]!=ti)
    	{
    		v[w]=ti;
    		ha[w].v=va;
    		ha[w].b=b;
    		ha[w].ne=-1;
    		return;
    	}
    	for(;ha[w].ne!=-1;w=ha[w].ne)
    		if(ha[w].b==b)
    			return;
    	ha[w].ne=++con;
    	ha[con].ne=-1;
    	ha[con].v=va;
    	ha[con].b=b;
    }
    int find(int w,int b)
    {
    	if(v[w]!=ti)
    		return 0;
    	for(;w!=-1;w=ha[w].ne)
    		if(ha[w].b==b)
    			return ha[w].v;
    	return 0;
    }
    int gcd(int a,int b)
    {
    	return b==0?a:gcd(b,a%b);
    }
    int ksm(int a,int b,int p)
    {
    	int r=1;
    	while(b)
    	{
    		if(b&1)
    			r=(long long)r*a%p;
    		a=(long long)a*a%p;
    		b>>=1;
    	}
    	return r;
    }
    int BSGS(int a,int b,int p)
    {
    	a%=p,b%=p;
    	if(b==1)
    		return 0;
    	int cnt=0,d=1;
    	for(int g=gcd(a,p);g!=1;g=gcd(a,p))
    	{
    		if(b%g)
    			return -1;
    		p/=g,b/=g;
    		d=(long long)d*a/g%p;
    		cnt++;
    		if(b==d)
    			return cnt;
    	}
    	con=mod,ti++;
    	int m=ceil(sqrt(p)),t=b;
    	for(int i=0;i<m;i++)
    	{
    		ins(t%mod,t,i);
    		t=(long long)t*a%p;
    	}
    	int g=ksm(a,m,p),now;
    	t=(long long)d*g%p;
    	for(int i=1;i<=m+1;i++)
    	{
    		if(now=find(t%mod,t))
    			return cnt+i*m-now;
    		t=(long long)t*g%p;
    	}
    	return -1;
    } 
    int main()
    {
    	while(scanf("%d%d%d",&a,&p,&b)&&a+b+p)
    	{
    		if(p==1)
    		{
    			puts("0");
    			continue;
    		}
    		ans=BSGS(a,b,p);
    		if(ans==-1)
    			puts("No Solution");
            else 
    			printf("%d
    ",ans);
    	}
    	return 0;
    }
    

    模板题:

    普通BSGS bzoj 3239 && 2480 http://www.cnblogs.com/lokiii/p/8359935.html
    扩展BSGS poj 3243 && 1467 http://www.cnblogs.com/lokiii/p/8360202.html
    其他题:

    bzoj 2242 http://www.cnblogs.com/lokiii/p/8360272.html
    bzoj 3122 http://www.cnblogs.com/lokiii/p/8360164.html

  • 相关阅读:
    Winform中如何禁用最大化或最小化按钮
    联想笔记本白屏解决办法
    SqlSever查询当前数据库某个表的名称、列名称、列说明
    离线安装Microsoft SQL Server 2016时Microsoft R Open和Microsoft R Server的问题
    SqlSever查询当前数据库的所有表名及其描述
    Windows10系统C盘的ESD文件夹是什么?可以删除吗?
    飞秋截图的快捷键是什么?
    打开Word时报错:Cannot find the Word document template:WordToRqm.dot
    .Net Core 2.1 上传文件后保存在根目录下的文件夹中,但是通过网页链接访问不了
    Winform弹出确认窗口
  • 原文地址:https://www.cnblogs.com/lokiii/p/8360445.html
Copyright © 2011-2022 走看看