这个我还是留在后面学吧。。。。有点小难。。。T_T.........
原创帖!转载请注明作者 AekdyCoin !
推论 2:
令 AA * A^b = B(mod C)
那么解存在的必要条件为: 可以得到至少一个可行解 A^b = X (mod C)
使上式成立
推论3
AA * A^b = B(mod C)
中解的个数为 (AA,C)
由推论3 不难想到对原始Baby Step Giant Step的改进
For I = 0 -> m
For any solution that AA * X = B (mod C)
If find X
Return I * m + j
而根据推论3,以上算法的复杂度实际在 (AA,C)很大的时候会退化到几乎O(C)
归结原因,是因为(AA,C)过大,而就是(A,C)过大
于是我们需要找到一中做法,可以将(A,C)减少,并不影响解
下面介绍一种“消因子”的做法
一开始D = 1 mod C
进行若干论的消因子,对于每次消因子
令 G = (A,C[i]) // C[i]表示经过i轮消因子以后的C的值
如果不存在 G | B[i] //B[i]表示经过i轮消因子以后的B的值
直接返回无解
否则
B[i+1] = B[i] / G
C[i+1] = C[i] / G
D = D * A / G
具体实现只需要用若干变量,细节参考代码
假设我们消了a'轮(假设最后得到的B,C分别为B',C')
那么有
D * A^b = B' (mod C')
于是可以得到算法
for i = 0 -> m
解 ( D* (A^m) ^i ) * X = B'(mod C')
由于 ( D* (A^m) ^i , C') = 1 (想想为什么?)
于是我们可以得到唯一解
之后的做法就是对于这个唯一解在Hash中查找
这样我们可以得到b的值,那么最小解就是a' + b !!
现在问题大约已近解决了,可是细心看来,其实还是有BUG的,那就是
对于
A^x = B(mod C)
如果x的最小解< a',那么会出错
而考虑到每次消因子最小消 2
故a'最大值为log(C)
于是我们可以暴力枚举0->log(C)的解,若得到了一个解,直接返回
否则必然有 解x > log(C)
PS.以上算法基于Hash 表,如果使用map等平衡树维护,那么复杂度会更大
要去做实验了,下午有空继续更新,下面是HDU 2815的代码
#include<iostream> #include<map> #include<cmath> using namespace std; typedef long long LL; int gcd(int a,int b){return b?gcd(b,a%b):a;} int ext_gcd(int a,int b,int& x,int& y){ int t,ret; if (!b){x=1,y=0;return a;} ret=ext_gcd(b,a%b,x,y); t=x,x=y,y=t-a/b*y; return ret; } int Inval(int a,int b,int n){ int x,y,e; ext_gcd(a,n,x,y); e=(LL)x*b%n; return e<0?e+n:e; } int pow_mod(LL a,int b,int c){LL ret=1%c;a%=c;while(b){if(b&1)ret=ret*a%c;a=a*a%c;b>>=1;}return ret;} int BabyStep(int A,int B,int C){ map<int,int> Hash; LL buf=1%C,D=buf,K; int i,d=0,tmp; for(i=0;i<=100;buf=buf*A%C,++i)if(buf==B)return i; while((tmp=gcd(A,C))!=1) { if(B%tmp)return -1; ++d; C/=tmp; B/=tmp; D=D*A/tmp%C; } Hash.clear(); int M=(int)ceil(sqrt((double)C)); for(buf=1%C,i=0;i<=M;buf=buf*A%C,++i)if(Hash.find((int)buf)==Hash.end())Hash[(int)buf]=i; for(i=0,K=pow_mod((LL)A,M,C);i<=M;D=D*K%C,++i) { tmp=Inval((int)D,B,C); if(tmp>=0&&Hash.find(tmp)!=Hash.end())return i*M+Hash[tmp]+d; } return -1; } int main() { int A,B,C; while(scanf("%d%d%d",&A,&C,&B)!=EOF) { if(B>=C){puts("Orz,I can’t find D!");continue;} int tmp=BabyStep(A,B,C); if(tmp<0)puts("Orz,I can’t find D!");else printf("%d\n",tmp); } return 0; } 下面是POJ Clever Y的代码(Hash还是相当快的) #include<iostream> #include<map> #include<cmath> using namespace std; typedef long long LL; const int maxn = 65535; struct hash{ int a,b,next; }Hash[maxn << 1]; int flg[maxn + 66]; int top,idx; void ins(int a,int b){ int k = b & maxn; if(flg[k] != idx){ flg[k] = idx; Hash[k].next = -1; Hash[k].a = a; Hash[k].b = b; return ; } while(Hash[k].next != -1){ if(Hash[k].b == b) return ; k = Hash[k].next; } Hash[k].next = ++ top; Hash[top].next = -1; Hash[top].a = a; Hash[top].b = b; } int find(int b){ int k = b & maxn; if(flg[k] != idx) return -1; while(k != -1){ if(Hash[k].b == b) return Hash[k].a; k = Hash[k].next; } return -1; } int gcd(int a,int b){return b?gcd(b,a%b):a;} int ext_gcd(int a,int b,int& x,int& y){ int t,ret; if (!b){x=1,y=0;return a;} ret=ext_gcd(b,a%b,x,y); t=x,x=y,y=t-a/b*y; return ret; } int Inval(int a,int b,int n){ int x,y,e; ext_gcd(a,n,x,y); e=(LL)x*b%n; return e<0?e+n:e; } int pow_mod(LL a,int b,int c){LL ret=1%c;a%=c;while(b){if(b&1)ret=ret*a%c;a=a*a%c;b>>=1;}return ret;} int BabyStep(int A,int B,int C){ top = maxn; ++ idx; LL buf=1%C,D=buf,K; int i,d=0,tmp; for(i=0;i<=100;buf=buf*A%C,++i)if(buf==B)return i; while((tmp=gcd(A,C))!=1){ if(B%tmp)return -1; ++d; C/=tmp; B/=tmp; D=D*A/tmp%C; } int M=(int)ceil(sqrt((double)C)); for(buf=1%C,i=0;i<=M;buf=buf*A%C,++i)ins(i,buf); for(i=0,K=pow_mod((LL)A,M,C);i<=M;D=D*K%C,++i){ tmp=Inval((int)D,B,C);int w ; if(tmp>=0&&(w = find(tmp)) != -1)return i*M+w+d; } return -1; } int main(){ int A,B,C; while(scanf("%d%d%d",&A,&C,&B)!=EOF,A || B || C){ B %= C; int tmp=BabyStep(A,B,C); if(tmp<0)puts("No Solution");else printf("%d\n",tmp); } return 0; }