• POJ 3243 clever Y


    扩展BSGS

    朴素BSGS只能处理模数 (p) 是质数的情况,但是对于其他情况,我们就可以用扩展BSGS解决
    计算 (a^x equiv b pmod p) ,如果 (gcd(a, p) == 1),那么就是朴素BSGS,如果 (gcd(a, p) ot = 1) ,根据带余除法的性质,我们可以在同余方程的 (a, p, b)同时除以一个数,方程的解不变.
    (d = gcd(a, p)) ,首先将 (a)(b) 都对 (p) 取模,然后特判, 如果 (b == 1),那么 (x) 一定等于 (0) ,如果 (a)(p) 的倍数,那么如果 (b) 也是 (p) 的倍数,那么答案是 (1) ,如果 (b)(1) ,那么答案是 (0) ,否则无解

    特判完了以后,判断 (d mid b) 是否成立, 如果不成立, 显然无解,如果成立,那么将这三个数同时除以 (d) ,原式变为 (a/b imes a^{x-1} equiv b/p mod (p/d)), 当然可能 (gcd(a, p/b) !=1),所以我们要不停的这么做,直到 (a)(p/d) 互质, 设我们这样做了 (k) 次,最后得到

    [frac {a^k} {prod_{i=1} ^ k d } imes a^{x -k} equiv frac b {prod_{i=1} ^ k d } pmod frac p {prod_{i=1} ^ k d } ]

    我们有可能在操作的过程中发现, (x<k),所以我们在每一步操作的时候都要判断一下等式是否成立,如果 (frac {a^k} {prod_{i=1} ^ k d} == frac b {prod_{i=1} ^ k d }),n那么答案就是 (k) ,如果在操作的过程中发现 (d mid b),那么(x) 只能是 (0) .

    如果以上情况都没有出现,那么就转化成了一个朴素BSGS问题,答案就是算下的结果加上 (k)

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #define ll long long
    using namespace std;
    ll a, b, p;
    struct HashTable{
    	static const int MOD = 99901, MAXN = 200005;
    	ll dat[MAXN], nxt[MAXN], head[MAXN], id[MAXN], nume;
    	void clear() {
    		memset(head, 0, sizeof(head));
    		memset(nxt, 0, sizeof(nxt));
    		nume = 0;
    	}
    	void insert(ll x, ll y){
    		ll tmp = x % MOD;
    		for(int i = head[tmp]; i; i = nxt[i]) {
    			if(dat[i] == x) {id[i] = y; return;}
    		}
    		dat[++nume] = x; id[nume] = y;
    		nxt[nume] = head[tmp]; head[tmp] = nume;
    	}
    	ll query(ll x) {
    		ll tmp = x % MOD;
    		for(int i = head[tmp]; i; i = nxt[i]) {
    			if(dat[i] == x) return id[i];
    		}
    		return -1;
    	}
    }Hash;
    ll gcd(ll a, ll b){
    	return !b ? a : gcd(b, a % b);
    }
    ll quick_mod(ll a, ll k, ll p) {
    	ll ans = 1;
    	while(k) {
    		if(k & 1ll) (ans *= a) %= p;
    		(a *= a) %= p;
    		k >>= 1;
    	}
    	return ans;
    }
    ll exBSGS(ll a, ll b, ll p) {
    	Hash.clear();
    	a %= p; b %= p;
    	if(b == 1) return 0;
    	if(!a){
    		if(!b) return 0;
    		return -1;
    	}
    	ll t, d = 1, k = 0;
    	do{
    		t = gcd(a, p);
    		if(b % t) return -1;
    		b /= t; p /= t;
    		(d *= a/t) %= p;
    		k++;
    		if(d == b) return k;
    	}while(t != 1);
    	ll m = ceil(sqrt(p)), tmp = b;
    	for(int i = 0; i <= m; i++) {
    		Hash.insert(tmp, i);
    		(tmp *= a) %= p;
    	}
    	ll g = quick_mod(a, m, p);
    	tmp = (d * g) % p;
    	for(int i =1; i <= m; i++) {
    		ll q = Hash.query(tmp);
    		if(q != -1) return i * m - q + k;
    		(tmp *= g) %= p;
    	}
    	return -1;
    }
    int main() {
    	while(cin >> a >> p >> b) {
    		if(!a && !p && !b) break;
    		ll t = exBSGS(a, b, p);
    		if(t == -1) printf("No Solution
    ");
    		else printf("%lld
    ", t);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Linux下链接mysql数据库的命令
    linux cp命令参数及用法详解
    svn命令在linux下的使用
    把一个一维数组转换为in ()
    JS修改标签中的文本且不影响其中标签
    Underscore template
    JavaScript动态加载js文件
    JavaScript库基本格式写法
    JavaScript class 使用
    Uncaught TypeError: Cannot read property 'ownerDocument' of null
  • 原文地址:https://www.cnblogs.com/Mr-WolframsMgcBox/p/8551108.html
Copyright © 2020-2023  润新知