• POJ3243 EXT-BSGS算法


    需要解决问题之前,首先要做到POJ2417,我的解决问题的方法:http://blog.csdn.net/wyfcyx_forever/article/details/40538515

    如今来看这个问题:AxB(mod C)

    已知A,B,C<=10^9,给定A,B,C,求x的最小整数解。

    注意这里的A,B,C没有不论什么限制!

    那么考虑我们的传统的GSBS算法为何不能解决问题:如果枚举的某个i,我们要利用拓展欧几里得求出存不存在某个A^j(0<=j<m),使得A^(i*m)*A*j%C=B.

    那么令A^j=x,我们其实要求的是一个二元方程的整数解:A^(i*m)x+Cy=B.我们知道有解当且仅当gcd(A,C)|B,然而眼下没有不论什么限制,显然是不一定满足的。

    我们要对算法进行一些改动。使得其能够进行上述的处理。详细证明去看AekdyCoin犇的题解,我就是简单讲一下我的理解。


    一開始的方程等价于A^x*a+C*b=B(a,b是整数)。如今gcd(A,C)!=1,最好还是令t=gcd(A,C)

    我们考虑方程(A/t)A^x'%(C/t)=(B/t)的解x'与原来的解x有什么关系。

    显然如今的方程等价于(A/t)A^x'*a'+(C/t)*b'=B/t.

    两端均乘以t得到:A^(x'+1)*a'+C*b'=B

    由系数相等有:x=x'+1,a=a',b=b'.

    那么我们就有一种方法算出x了。先算出x',再加上1即可了。

    考虑怎样求出x',如今的方程假设A,C依然不互质,就继续迭代将系数除以最大公约数。同一时候前面的常数增大。

    然后求出解之后再加上总共除的次数就好了。


    Code:

    #include <cmath>
    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <climits>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    typedef long long LL;
    inline LL gcd(LL a, LL b) {
    	return (!b) ? a : gcd(b, a % b);
    }
    inline void Exgcd(LL a, LL b, LL &d, LL &x, LL &y) {
    	if (!b) { d = a, x = 1, y = 0; }
    	else { Exgcd(b, a % b, d, y, x), y -= x * (a / b); }
    }
    inline LL Solve(LL a, LL b, LL c) {// ax%c=b S.T. (a,c)=1
    	LL d, x, y;
    	Exgcd(a, c, d, x, y);
    	x = (x + c) % c;
    	return x * b % c;
    }
    inline LL Ksm(LL x, LL y, LL p) {
    	LL res = 1, t = x;
    	for(; y; y >>= 1) {
    		if (y & 1) res = res * t % p;
    		t = t * t % p;
    	}
    	return res;
    }
    
    #define mod 1313131
    struct Hashset {
    	int head[mod], next[35010], f[35010], v[35010], ind;
    	void reset() {
    		ind = 0;
    		memset(head, -1, sizeof head);
    	}
    	void Insert(int x, int _v) {
    		int ins = x % mod;
    		for(int j = head[ins]; j != -1; j = next[j])
    			if (f[j] == x) {
    				v[j] = min(v[j], _v);
    				return;
    			}
    		f[ind] = x, v[ind] = _v;
    		next[ind] = head[ins], head[ins] = ind++;
    	}
    	int operator [] (const int &x) const {
    		int ins = x % mod;
    		for(int j = head[ins]; j != -1; j = next[j])
    			if (f[j] == x)
    				return v[j];
    		return -1;
    	}
    }S;
    
    LL BSGS(LL C, LL A, LL B, LL p) {// A^x%p=B S.T.(A,p)=1
    	if (p <= 100) {
    		LL d = 1;
    		for(int i = 0; i < p; ++i) {
    			if (d == B)
    				return i;
    			d = d * A % p;
    		}
    		return -1;
    	}
    	else {
    		int m = (int)sqrt(p);
    		S.reset();
    		LL d = 1, Search;
    		for(int i = 0; i < m; ++i) {
    			S.Insert(d, i);
    			d = d * A % p;
    		}
    		for(int i = 0; i * m < p; ++i) {
    			d = Ksm(A, i * m, p) * C % p;
    			Search = S[Solve(d, B, p)];
    			if (Search != -1)
    				return i * m + Search;
    		}
    		return -1;
    	}
    }
    
    int main() {
    	LL x, z, k;
    	register LL i, j;
    	while(scanf("%I64d%I64d%I64d", &x, &z, &k) == 3 && (x + z + k)) {
    		LL d = 1;
    		bool find = 0;
    		for(i = 0; i < 100; ++i) {
    			if (d == k) {
    				printf("%I64d
    ", i);
    				find = 1;
    				break;
    			}
    			d = d * x % z;
    		}
    		if (find)
    			continue;
    		
    		LL t, C = 1, num = 0;
    		bool failed = 0;
    		while((t = gcd(x, z)) != 1) {
    			if (k % t != 0) {
    				failed = 1;
    				break;
    			}
    			z /= t;
    			k /= t;
    			C = C * x / t % z;
    			++num;
    		}
    		
    		if (failed) {
    			puts("No Solution");
    			continue;
    		}
    		
    		LL res = BSGS(C, x, k, z);
    		if (res == -1)
    			puts("No Solution");
    		else
    			printf("%I64d
    ", res + num);
    	}
    	
    	return 0;
    }


    版权声明:本文博客原创文章。博客,未经同意,不得转载。

  • 相关阅读:
    关于Java中变量的意义和注意事项
    成为Android高手的十个建议
    成为Java高手的25个学习目标(经典)
    流体力学神器:Naiad 0.6 Windows版试用
    饭前念诵+感恩辞+感恩白開水
    Android 基本开发规范(必读)
    Python批量重命名Maya场景中的3D物体
    Java高新技术视频笔记:反射
    程序员编程技术迅速提高的终极攻略
    三十、有关联网问题
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/4660834.html
Copyright © 2020-2023  润新知