zoukankan      html  css  js  c++  java
  • BSGS学习记录/POJ 3696 The Luckiest number

    BSGS

    BSGS(baby-step giant-step),即大步小步算法。常用于求解离散对数问题。形式化地说,该算法可以在 (O(sqrt{p})) 的时间内求解

    [a^x equiv b pmod p ]

    其中 (aperp p)。方程的解 (x) 满足 (0 le x < p)。(在这里需要注意,只要 (aperp p) 就行了,不要求 (p) 是素数)

    算法描述

    (x = A left lceil sqrt p ight ceil - B),其中 (0le A,B le left lceil sqrt p ight ceil),则有 (a^{Aleft lceil sqrt p ight ceil -B} equiv b pmod p),稍加变换,则有 (a^{Aleft lceil sqrt p ight ceil} equiv ba^B pmod p)

    我们已知的是 (a,b),所以我们可以先算出等式右边的 (ba^B) 的所有取值,枚举 (B),用 hash/map 存下来,然后逐一计算 (a^{Aleft lceil sqrt p ight ceil}),枚举 (A),寻找是否有与之相等的 (ba^B),从而我们可以得到所有的 (x)(x=A left lceil sqrt p ight ceil - B)

    注意到 (A,B) 均小于 (left lceil sqrt p ight ceil),所以时间复杂度为 (Thetaleft (sqrt p ight )),用 map 则多一个 (log)

    上述介绍在CC BY-SA 4.0SATA条款下,转自OIWIKI

    P3846 [TJOI2007] 可爱的质数

    模板

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    unordered_map<ll,ll> mp;
    
    int main(){
    	ll p,a,b;
    	scanf("%lld%lld%lld",&p,&a,&b);
    	ll sqp=ceil(sqrt(p));//square root of p
    	ll rs=b,ap=1,ls=1;//rs/ls: right/left side
    	//ap: sqp-th power of a
    	for(int i=1;i<=sqp;++i){
    		rs=(rs*a)%p;
    		ap=(ap*a)%p;
    		mp[rs]=i;
    	}
    	for(int i=1;i<=sqp;++i){
    		ls=(ls*ap)%p;// ls=a^{i*sqrt{p}}
    		if(mp[ls]){
    			printf("%lld
    ",((i*sqp-mp[ls])%p+p)%p);
    			return 0;
    		}
    	}
    	puts("no solution");
    	return 0;
    }
    

    POJ The Luckiest number

    (underbrace{888 cdots88}_{ ext{x个}}equiv 0space (modspace L)最小的符合条件的正整数x).

    ((10^x-1) cdotfrac{8}{9}equiv0space(modspace L))

    (9n|8(10^x-1))

    (ecause gcd(8,9)=1,gcd(frac{n}{gcd(L,8)},frac{L}{gcd(L,8)})=1)

    ( herefore 10^xequiv1(modspace frac{9n}{gcd(L,8)}))

    注意到与此时x应严格大于0,在处理时,不能使 (x=A left lceil sqrt p ight ceil - B)(a^{Aleft lceil sqrt p ight ceil} equiv ba^B pmod p))的B不能为(left lceil sqrt p ight ceil),第一次循环处理到(left lceil sqrt p ight ceil-1).

    时间复杂度(O(sqrt L))

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<utility>
    using namespace std;
    typedef long long ll;
    #define N 150000
    ll hs[N],nxt[N],hd[N],val[N];
    ll cnt;
    
    void ins(ll x,ll v){
    	ll p=x%N;
    	hs[++cnt]=x;
    	val[cnt]=v;
    	nxt[cnt]=hd[p];
    	hd[p]=cnt;
    }
    
    ll fd(ll x){
    	ll p=x%N;
    	for(ll i=hd[p];i!=-1;i=nxt[i]){
    		if(hs[i]==x){
    			return val[i];
    		}
    	}
    	return -1;
    }
    
    ll __gcd(ll a,ll b){
    	return b==0?a:__gcd(b,a%b);
    }
    
    ll mul(ll a,ll b,ll c){
    	if(a<b){
    		swap(a,b);
    	}
    	ll ret=0,tmp=a;
    	while(b){
    		if(b&1){
    			ret+=tmp;
    			if(ret>=c) ret-=c;	
    		}
    		tmp<<=1;
    		if(tmp>=c) tmp-=c;
    		b>>=1;
    	}	
    	return ret%c;
    }
    
    int main(){
    	ll n;
    	ll cs=0;
    	while(scanf("%lld",&n),n){
    		cnt=0;
    		memset(hd,-1,sizeof hd);
    		ll p=9*n/__gcd(n,8ll),a=10,b=1;
    		if(__gcd(p,a)!=1){
    			printf("Case %lld: 0
    ",++cs);
    			continue;
    		}
    		ll sqp=ceil(sqrt((double)p));//square root of p
    		ll rs=b,ap=1,ls=1;//rs/ls: right/left side
    		//ap: sqp-th power of a
    		for(ll i=1;i<sqp;++i){
    			rs=(rs*a)%p;
    			ap=(ap*a)%p;
    			ins(rs,i);
    		}
    		if(sqp) ap=(ap*a)%p;
    		bool f=0;
    		for(ll i=1;i<=sqp;++i){
    			ls=mul(ls,ap,p);// ls=a^{i*sqrt{p}}
    			ll j;
    			if((j=fd(ls))!=-1){
    				f=1;
    				printf("Case %lld: %lld
    ",++cs,((i*sqp-j)%p+p)%p);
    				break;
    			}
    		}
    		if(!f){
    			printf("Case %lld: 0
    ",++cs);
    		}
    	}
    	return 0;
    }
    

    另外本题还有另一种解法

    易证:(aperp n, a^x equiv 1(modspace n))的最小整数解使(varphi(n))的约数,枚举约数即可。

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<utility>
    #include<iostream>
    using namespace std;
    typedef long long ll;
    
    ll __gcd(ll a,ll b){
    	return b==0?a:__gcd(b,a%b);
    }
    
    ll mul(ll a,ll b,ll c){
    	if(a<b){
    		swap(a,b);
    	}
    	ll ret=0,tmp=a;
    	while(b){
    		if(b&1){
    			ret+=tmp;
    			if(ret>=c) ret-=c;	
    		}
    		tmp<<=1;
    		if(tmp>=c) tmp-=c;
    		b>>=1;
    	}	
    	return ret%c;
    }
    
    ll qpow(ll a,ll b,ll c){
    	ll ret=1,tmp=a;
    	while(b){
    		if(b&1){
    			ret=mul(ret,tmp,c);
    		}
    		tmp=mul(tmp,tmp,c);
    		b>>=1;
    	}
    	return ret%c;
    }
    
    int main(){
    	ll n;
    	ll cs=0;
    	while(scanf("%lld",&n),n){
    		ll p=9*n/__gcd(n,8ll);
    		if(__gcd(p,10)!=1){
    			printf("Case %lld: 0
    ",++cs);
    			continue;
    		}
    		ll fai=p,t=p,r=sqrt(p);
    		for(ll i=2;i<=r;++i){
    			if(t%i==0){
    				fai=fai/i*(i-1);
    				t/=i;
    				while(t%i==0){
    					t/=i;
    				}	
    			}
    		}
    		if(t>1){
    			fai=fai/t*(t-1);
    		}
    		r=sqrt(fai);
    		ll ans=1e18;
    		bool f=0;
    		for(ll i=1;i<=r;++i){
    			if(fai%i==0){
    				if(qpow(10,i,p)==1){
    					ans=min(ans,i);
    					f=1;
    				}
    				if(qpow(10,fai/i,p)==1){
    					ans=min(ans,fai/i);
    					f=1;
    				}
    			}
    		}
    		printf("Case %lld: %lld
    ",++cs,f?ans:0);
    	}
    	return 0;
    }
    
  • 相关阅读:
    JS中的getter与setter
    Node.js中exports与module.exports的区别
    JS中的匿名函数自执行、函数声明与函数表达式
    JS实现千分位
    JS中的new操作符原理解析
    JS中null与undefined的区别
    JavaScript中callee与caller,apply与call解析
    解决vue路由与锚点冲突
    jQuery中deferred的对象使用
    Vue的生命周期
  • 原文地址:https://www.cnblogs.com/chwhc/p/14523911.html
Copyright © 2011-2022 走看看