zoukankan      html  css  js  c++  java
  • [SDOI2011][洛谷P2485]计算器(BSGS模板)

    题面

    https://www.luogu.com.cn/problem/P2485

    题解

    对于T=1,快速幂即可。
    对于T=2,exgcd即可。
    重点是T=3,需要使用BSGS算法。

    BSGS算法

    用来快速求解形如({a^x}{equiv}r(mod p))的指数同余方程的算法,适用范围是(gcd(a,p)=1)
    由欧拉-费马定理可得(a^{phi(p)}{equiv}1(mod p))。下设(0<=x<{phi(p)})
    设置“间隔”(T),那么x一定可以表示成(iT-j)(其中(1<=j<=T))的形式。下有

    [a^{iT-j}{equiv}r{mod p} ]

    [a^{iT}{equiv}r*a^j{mod p} ]

    故只要某一个(a^{iT}(1<=i<={lceil{{phi(p)-1}over{T}} ceil}))以及某一个(r*a^j(1<=j<=T))相等,就得到了一个解(x=iT-j)

    实现时只需要将所有的(r*a^j)预处理好放入Hash表内,在计算(a^{iT})的时候同步查询就可以了。

    计算(r*a^j)的时间复杂度为(O(T)),计算(a^{iT})的时间复杂度是(O({{phi(p)}over{T}})),取(T=sqrt{phi(p)})即可保证总时间复杂度是(O(sqrt{phi(p)}))

    回本题

    给出(y),(z),(p),计算满足(y^x{equiv}z{mod{p}})的最小非负整数 (x)

    保证(p)是质数。

    首先考虑(p|y)的情况,即({gcd}(y,p){ ot=}1)的情况,此时不能适用BSGS算法

    • 1、(z=0)(x=1)即可
    • 2、(z=1)(x=0)即可
    • 3、others:无解

    其他情况可以适用BSGS解决。

    代码

    #include<bits/stdc++.h>
    
    using namespace std;
    
    #define ll long long
    #define rg register
    
    inline ll read(){
    	ll s = 0,ww = 1;
    	char ch = getchar();
    	while(ch < '0' || ch > '9'){if(ch == '-')ww = -1;ch = getchar();}
    	while('0' <= ch && ch <= '9'){s = 10 * s + ch - '0';ch = getchar();}
    	return s * ww;
    }
    
    inline void write(ll x){
    	if(x < 0)putchar('-'),x = -x;
    	if(x > 9)write(x / 10);
    	putchar('0' + x % 10);
    }
    
    ll mod,g;
    
    inline ll check(ll x){
    	return (x % mod + mod) % mod;
    }
    
    namespace ModCalc{
    	inline void Inc(ll &x,ll y,ll mod){
    		x += y;if(x >= mod)x -= mod;
    	}
    	
    	inline void Dec(ll &x,ll y,ll mod){
    		x -= y;if(x < 0)x += mod;
    	}
    	
    	inline ll Add(ll x,ll y,ll mod){
    		Inc(x,y,mod);return x;
    	}
    	
    	inline ll Sub(ll x,ll y,ll mod){
    		Dec(x,y,mod);return x;
    	}
    }
    using namespace ModCalc;
    
    inline ll power(ll a,ll n){
    	ll x = a,s = 1;
    	while(n){
    		if(n & 1)s = s * x % mod;
    		x = x * x % mod;
    		n >>= 1;
    	}
    	return s;
    }
    
    inline ll exgcd(ll a,ll &x,ll b,ll &y){
    	if(!b){
    		x = 1,y = 0;
    		return a;
    	}
    	ll g = exgcd(b,y,a%b,x);
    	y -= a / b * x;
    	return g; 
    }
    
    map<ll,ll>M;
    
    int main(){
    	ll T = read(),opt = read();
    	if(opt == 1){
    		while(T--){
    			ll a = read(),n = read();
    			mod = read();a %= mod;
    			write(power(a,n));putchar('
    ');
    		}
    	}
    	else if(opt == 2){
    		while(T--){
    			ll a = read(),r = read();
    			mod = read();
    			ll x,y;
    			ll g = exgcd(a,x,mod,y);
    			if(r % g != 0){
    				puts("Orz, I cannot find x!");
    				continue;
    			}
    			a /= g,r /= g,mod /= g;
    			x = check(x * r);
    			write(x);putchar('
    ');
    		}
    	}
    	else{
    		while(T--){
    			ll a = read(),r = read();
    			mod = read();a %= mod,r %= mod;
    			if(!a){
    				if(!r)puts("1");
    				else if(r == 1)puts("0");
    				else puts("Orz, I cannot find x!");
    				continue;
    			}
    			ll T = (ll)round(sqrt(mod));
    			ll a_T = power(a,T);
    			M.clear();
    			for(rg ll i = 1,cur = r * a % mod;i <= T;i++,cur = cur * a % mod)M[cur] = i;
    			ll flag = 0;
    			for(rg ll i = 1,cur = a_T;i * T - T <= mod - 2;i++,cur = cur * a_T % mod)if(M.count(cur)){
    				write(Sub(i*T%(mod-1),M[cur],mod-1)),putchar('
    ');
    				flag = 1;
    				break;
    			}
    			if(!flag)puts("Orz, I cannot find x!");
    		}
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    ABP WebApi的请求类型
    对服务器的文件或文件夹压缩
    VS运行遇到的那些坑
    asp.net core Api集成Swagger
    通过文件路径获取文件名
    读取服务器或者本地的文件夹下面的文件
    计算出 3 至 1000 范围内最大的十个素数,放入数组中,并计算出其累加和。
    LINUX 无法登入系统(2017-1-16)
    zynq里面的AXI总线(2017-1-11)
    学习随笔(2017-1-10)
  • 原文地址:https://www.cnblogs.com/xh092113/p/12255049.html
Copyright © 2011-2022 走看看