zoukankan      html  css  js  c++  java
  • BSGS及扩展BSGS总结(BSGS,map)

    蒟蒻哪里有什么总结,只能点击%YL%

    还有这位ZigZagK大佬的blog

    (mbox{BSGS})

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

    给定(a,b)和模数(mbox{YL}),求(a^xequiv b(modmbox{YL}))(x)的最小非负整数解。保证(gcd(a,mbox{YL})=1)

    (k=lceilsqrt{mbox{YL}} ceil),令(x=ky-c)(yin[1,k],cin[0,k)),故分解唯一)

    于是有(a^{ky}equiv ba^c(modmbox{YL}))

    两边的取值都只有(k)种,枚举右边丢进map,再枚举左边查找一下即可得到最小的解。

    复杂度(O(sqrt{mbox{YL}}logsqrt{mbox{YL}}))。注意特判掉一些特殊情况。

    #include<bits/stdc++.h>
    #define LL long long
    #define RG register
    #define R RG int
    using namespace std;
    map<int,int>c;
    inline LL qpow(RG LL b,R k,RG LL YL){//快速幂
    	RG LL a=1;
    	for(;k;k>>=1,b=b*b%YL)
    		if(k&1)a=a*b%YL;
    	return a;
    }
    int main(){
    	R a,b,YL;
    	cin>>YL>>a>>b;
    	if((b%=YL)==1)return puts("0"),0;//特判×2
    	if((a%=YL)==0)return puts("no solution"),0;
    	R k=sqrt(YL)+1,y;
    	RG LL p,pw=qpow(a,k,YL);
    	for(p=b,y=0;y<k;++y,(p*=a)%=YL)//预处理
    		c[(int)p]=y;
    	for(p=pw,y=1;y<=k;++y,(p*=pw)%=YL)//查找
    		if(c.count((int)p))return(cout<<(LL)k*y-c[(int)p]<<endl),0;
    	return puts("no solution"),0;//找不到
    }
    

    扩展(mbox{BSGS})

    模板题:洛谷P4195 Spoj3105 Mod
    双倍经验:洛谷SP3105 MOD - Power Modulo Inverted

    可以解决(gcd(a,mbox{YL}) eq1)的情况,核心思想是试探性地约去(gcd)

    同余方程(a^xequiv b(modmbox{YL})),可以提一个(a)出来改成不定方程(acdot a^{x-1}+mbox{YL}cdot y=b),等于说暂时把(a^{x-1})看成了未知数。

    (g=gcd(a,mbox{YL})),学完exgcd之后我们就知道了如果(g mid b)则方程组无解。否则就可以约成(frac a gcdot a^{x-1}+frac{mbox{YL}}gcdot y=frac b g)

    我们把约简后的方程看作一个新的不定方程(a'cdot a^{x-1}+mbox{YL}'cdot y=b'),如果(gcd(a,mbox{YL}'))还是不为(1)的话,我们就再从幂里面拿出一个(a)(mbox{YL}')约。如此循环。

    终于在约了(cnt)次后,我们得到了一个(gcd=1)的方程了,变回来就是(a'cdot a^{x-cnt}equiv b'(modmbox{YL}'))

    接下来的解法已经属于常规(mbox{BSGS})了,不过因为一些细节上的区别还是再写一遍。

    仍然设(k=lceilsqrt{mbox{YL}'} ceil),令(x=ky-c)(yin[1,k],cin[0,k))

    于是有(a'cdot a^{ky}equiv ba^{cnt}cdot a^c(modmbox{YL}')),其实只是恒等号两边多乘了点东西而已。

    约分多出来的复杂度是(O(log^2mbox{YL})),因为最多被约(log)次,它的阶小于根号就忽略掉了。又要注意一些特判。

    #include<bits/stdc++.h>
    #define LL long long
    #define RG register
    #define R RG int
    using namespace std;
    map<int,int>c;
    inline LL qpow(RG LL b,R k,RG LL YL){
        RG LL a=1;
        for(;k;k>>=1,b=b*b%YL)
            if(k&1)a=a*b%YL;
        return a;
    }
    int gcd(R x,R y){
        return y?gcd(y,x%y):x;
    }
    int main(){
        R a,b;RG LL YL;
        cin>>a>>YL>>b;
        while(a||b||YL){
            R x=-1,a1=1,cnt=0,g,k,y,p,pw;
            a%=YL;
            if((b%=YL)==1){x=0;goto L;}//这个特判上面提过
            while((g=gcd(a,YL))!=1){
                if(b%g)goto L;//无解充要条件
                ++cnt;b/=g;YL/=g;
                a1=a/g*(LL)a1%YL;
                if(a1==b){x=cnt;goto L;}
            }//注意这个特判,此时等价于a^{x-cnt}≡1(mod YL)
            c.clear();//多组数据注意清空
            k=sqrt(YL)+1;//常规BSGS过程
            pw=qpow(a,k,YL);
            p=b*qpow(a,cnt,YL)%YL;
            for(y=0;y<k;++y,p=(LL)p*a%YL)
                c[p]=y;
            p=(LL)a1*pw%YL;//多乘一个a1
            for(y=1;y<=k;++y,p=(LL)p*pw%YL)
                if(c.count(p)){x=k*y-c[p];break;}
          L:~x?printf("%d
    ",x):puts("No Solution");
            cin>>a>>YL>>b;
        }
        return 0;
    }
    
  • 相关阅读:
    Java实现 蓝桥杯VIP 算法训练 字符删除
    Java实现 蓝桥杯VIP 算法训练 字符删除
    Java实现 蓝桥杯VIP 算法训练 字符删除
    Java实现 蓝桥杯VIP 算法训练 字符删除
    Java实现 蓝桥杯VIP 算法训练 字符删除
    Java实现 蓝桥杯VIP 算法训练 字符串编辑
    Java实现 蓝桥杯VIP 算法训练 字符串编辑
    Java实现 蓝桥杯VIP 算法训练 字符串编辑
    Java实现 蓝桥杯VIP 算法训练 字符串编辑
    Java实现 蓝桥杯VIP 算法训练 字符串编辑
  • 原文地址:https://www.cnblogs.com/flashhu/p/9737769.html
Copyright © 2011-2022 走看看