• POJ 2417 Discrete Logging


    BSGS

    用于求解形如 (a^x equiv b pmod p) 的高次同余方程的方法

    BSGS(Baby Step, Giant Step), 大步小步(拔山盖世)

    我们将 (x) 写成如下形式 $x = i * t - j $ 其中 (t = sqrt p) , $ 0 leq j leq t$ (为了遍历到 (x = 0)的情况,所以我们使 (j) 可以等于 (t) ,当然也可以特判 $x = 0 $的情况)

    所以原公式可化为 $$a ^ {i * t} equiv b imes a^j pmod p$$

    我们可以预处理出 (b imes a ^ j pmod p) 的所有值,存入Hash表(用map也可以,但是多一个log),如果对于两个不同的 (j) ,算下的值是一样的,因为我们要求的是最小的 (x) ,我们可以贪心的存最大的 (j) .

    首先特判,(a) 是否是 (p) 的倍数,如果是根据 (b) 的值输出答案,
    然后从小到大枚举 (i) ,计算 (a^{i*t} pmod p),如果对于某个 (i) 来说,计算下的值在Hash表里面出现过,那么答案就是 (i*t - j)

    根据欧拉定理 (a^x equiv a^{x + varphi (p)} pmod p)
    所以如果 (x) 没有出现在 (varphi (p)) 的范围以内,那么就无解

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #define ll long long
    using namespace std;
    ll p, a, b, n, opt;
    struct HashTable{
    	static const int MOD = 99901, MAXN = 200005;
    	ll head[MAXN], nxt[MAXN], dat[MAXN], id[MAXN], nume;
    	void clear(){
    		memset(head, 0, sizeof(head));
    		memset(nxt, 0, sizeof(nxt));
    		nume = 0;
    	}
    	void insert(ll x, ll y) {
    		for(int i = head[x % MOD]; i ; i = nxt[i]){
    			if(dat[i] == x) {id[i] = y;return;}
    		}
    		dat[++nume] = x;
    		id[nume] = y;
    		nxt[nume] = head[x % MOD];
    		head[x % MOD] = nume;
    	}
    	ll query(ll x) {
    		for(int i = head[x % MOD] ; i; i = nxt[i]) {
    			if(dat[i] == x) return id[i];
    		}
    		return -1;
    	}
    }Hash;
    ll quick_mod(ll n, ll k, ll p) {
    	ll ans = 1;
    	while(k) {
    		if(k & 1ll) (ans *= n) %= p;
    		(n *= n) %= p;
    		k >>= 1;
    	}
    	return ans;
    }
    int main() {
    	while(cin >> p >> a >> b){
    		Hash.clear();
    		ll t = ceil(sqrt(p));
    		if(!(a % p)){
    			if(b % p == 1) printf("0
    ");
    			else if(b % p == 0) printf("1
    ");
    			else printf("no solution
    ");
    			continue;
    		}
    		for(int i = 0 ; i <= t ; i++) {
    			ll k = b * quick_mod(a, i, p) % p;
    			Hash.insert(k, i);
    		}
    		ll ans = 1, tmp = quick_mod(a, t, p);
    		bool f = 0;
    		for(int i = 1; i <= t; i++) {
    			(ans *= tmp) %= p;
    			ll j = Hash.query(ans);
    			if(j != -1) {f = 1; printf("%lld
    ", i * t - j);break;}
    		}
    		if(!f) printf("no solution
    ");
    	}
    	return 0;
    }
    
  • 相关阅读:
    Lambda表达式
    多态之美
    集合那点事
    程序员艺术家
    MySQL:如何导入导出数据表和如何清空有外建关联的数据表
    Ubuntu修改桌面为Desktop
    shutil.rmtree()
    SCP命令
    kickstart
    数据哈希加盐
  • 原文地址:https://www.cnblogs.com/Mr-WolframsMgcBox/p/8548453.html
Copyright © 2020-2023  润新知