标签:
Time Limit: 5000MS | Memory Limit: 65536K | |
Total Submissions: 7259 | Accepted: 1795 |
Description
Little Y finds there is a very interesting formula in mathematics:
XY mod Z = K
Given X, Y, Z, we all know how to figure out K fast. However, given X,Z,K, could you figure out Y fast?
Input
Output
Sample Input
5 58 33
2 4 3
0 0 0
Sample Output
9
No Solution
Source
X^Y%Z=K,计算等式成立的最小的Y值。
扩展BSGS算法,普通BSGS算法要求 A^x≡B( mod C )的C值为质数,因为等式有解的要求是GCD(A,C)|B,只有当C为质数,才一定成立。而此题并没有说C一定为质数。所以就要用到EXT-BSGS算法,看这个算法也是理解了好久。网上参考讲解这个算法的不多,找资料都找好久。自己总结下这个算法。
首先必须要会普通的BSGS,普通BSGS算法讲解:点击打开链接
我们知道,普通的BSGS算法可以处理C为质数的情况,也就是保证GCD(A,C)|B,所以我们只要保证出现这种情况即可。怎么才能出现这种情况?我们可以让GCD(A,C)=1,这样就能保证它一定能被B整除。
如何能让(A,C)=1?我们可以一直让C,除以(A,C)。当C把所有的A,C的公约数除尽之后,(A,C)一定等于1。注意,再求(A,C)时,C值是变换后的C值,即C[i]=C[i] / ( A,C[i-1] )。
为了保证等式成立,我们必须用等式的每部分都除以这个值。我们一直循环C/(A,C),B/(A,C),而A^x的值不是A/(A,C)这点要注意。除的时候我们考虑的是从A^x次方中取出一个A除以(A,C),这时:A^x=A/(A,C)*A^(x-1)。
我们的循环操作截止到(A,C)=1,所以在经过cnt次的操作后A^x=D*A^(x-cnt),因为我们总共取出cnt个A。我们每次循环还要更新D值,就是每次A/(A,C)的值乘以上次循环的值。即循环的是:D=D*A/(A,C)。所以我们这里D≠A^cnt。这点要注意一下。
我们经过上述操作之后等式变成 D*A^(x′)≡B′ ( mod C′ ),x′=x-cnt。此时 只要我们求解出这个等式的解x′,就能求出x的值,x=x′+cnt。因为A*D≡B*D( mod C*D )等价于A≡B( mod C )。所以我们求得的解是等价的。
而且在这里面我们(A,C)=1,这时我们就可以直接利用普通BSGS求解。
等价为 A^(i*M)*D*A^j≡B( mod C )。我们查找合适的j值就可以了。
最后我们还有一个重要的的问题没解决,我们看一个例子:49^x≡0( mod 343),很显然x=0,但是如果根据我们上述方法得出的结果就会是2。这里答案就显然变得不对,这里我们会发现答案如果本身小于cnt,再加上cnt的话就会变成一个不正确的值,所以我们可以尝试枚举一下所有小于cnt的x值,看下x值是否存在。如果存在的话直接返回x值即可,不用再进行BSGS步骤了。因为C每次最小消去的因子是2,所以cnt最大是log(C),我们枚举[0,log(C)]值就可以了。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <algorithm> using namespace std; const int MAXN = 1000010; typedef long long LL; bool hash[MAXN]; LL p[MAXN]; LL var[MAXN]; void insert_x(LL n,LL v) { int x=v%MAXN; while(hash[x]&&var[x]!=v){ x++; if(x==MAXN) x=0; } if(!hash[x]){ p[x]=n; var[x]=v; hash[x]=true; } } LL find_x(LL v) { int x=v%MAXN; while(hash[x]&&var[x]!=v){ x++; if(x==MAXN) x=0; } if(hash[x]) return p[x]; return -1; } LL gcd(LL a,LL b) { if(b==0) return a; return gcd(b,a%b); } LL exgcd(LL a,LL b,LL &x,LL &y) { if(b==0){ x=1;y=0; return a; } LL r=exgcd(b,a%b,x,y); LL t=x; x=y; y=t-a/b*y; return r; } LL BSGS(LL A,LL B,LL C) { LL n=1; for(int i=0;i<110;i++){//枚举所有小于log(C)的x值 if(n==B%C) return i; n=n*A%C; } int cnt=0; LL res=1; LL divisor=gcd(A,C); while(divisor!=1){ //消去(A,C)的所有公约数 if(B%divisor){ return -1; } C/=divisor; B/=divisor; res=res*A/divisor%C; divisor=gcd(A,C); cnt++; } LL M=ceil(sqrt(C*1.0)); LL temp=1; for(int i=0;i<M;i++){ insert_x(i,temp); temp=temp*A%C; } for(int i=0;i<M;i++){ LL x,y; LL r=exgcd(res,C,x,y); x=x*B; x=(x%C+C)%C; LL coordinate=find_x(x); if(coordinate!=-1){ return (i*M+coordinate+cnt); } res=res*temp%C; } return -1; } int main() { LL X,Z,K; while(scanf("%lld%lld%lld",&X,&Z,&K)!=EOF){ if(!X&&!Z&&!K)break; memset(hash,false,sizeof(hash)); memset(var,-1,sizeof(var)); memset(p,-1,sizeof(p)); LL coordinate=BSGS(X,K,Z); if(coordinate==-1) printf("No Solution\n"); else printf("%lld\n",coordinate); } return 0; }
版权声明:本文为博主原创文章,转载请注明出处。
【EXT-BSGS算法求离散对数】POJ Clever Y 3243
标签:
原文地址:http://blog.csdn.net/ydd97/article/details/48060553