baby_step giant_step hdu 2815 mod tree pku 3243 Clever Y
2011-08-05 16:31
549 查看
原创帖!转载请注明作者AekdyCoin!
【普通BabyStepGiantStep】
【问题模型】
求解
A^x=B(modC)中0<=x<C的解,C为素数
【思路】
我们可以做一个等价
x=i*m+j(0<=i<m,0<=j<m)m=Ceil(sqrt(C))
而这么分解的目的无非是为了转化为:
(A^i)^m*A^j=B(modC)
之后做少许暴力的工作就可以解决问题:
(1)fori=0->m,插入Hash(i,A^imodC)
(2)枚举i,对于每一个枚举到的i,令AA=(A^m)^imodC
我们有
AA*A^j=B(modC)
显然AA,B,C均已知,而由于C为素数,那么(AA,C)无条件为1
于是对于这个模方程解的个数唯一(可以利用扩展欧几里得或欧拉定理来求解)
那么对于得到的唯一解X,在Hash表中寻找,如果找到,则返回i*m+j
注意:由于i从小到大的枚举,而Hash表中存在的j必然是对于某个剩余系内的元素X是最小的(就是指标)
所以显然此时就可以得到最小解
如果需要得到x>0的解,那么只需要在上面的步骤中判断当i*m+j>0的时候才返回
到目前为止,以上的算法都不存在争议,大家实现的代码均相差不大。可见当C为素数的时候,此类离散对数的问题可以变得十分容易实现。
【扩展BabyStepGiantStep】
【问题模型】
求解
A^x=B(modC)中0<=x<C的解,C无限制(当然大小有限制……)
【写在前面】
这个问题比较麻烦,目前网络上流传许多版本的做法,不过大部分已近被证明是完全错误的!
这里就不再累述这些做法,下面是我的做法(有问题欢迎提出)
下面先给出算法框架,稍后给出详细证明:
(0)fori=0->50if(A^imodC==B)returniO(50)
(1)d<-0D<-1modC
while((tmp=gcd(A,C))!=1)
{
if(B%tmp)return-1;//无解!
++d;
C/=tmp;
B/=tmp;
D=D*A/tmp%C;
}
(2)m=Ceil(sqrt(C))//Ceil是必要的O(1)
(3)fori=0->m插入Hash表(i,A^imodC)O(m)
(4)K=pow_mod(A,m,C)
fori=0->m
解D*X=B(modC)的唯一解(如果存在解,必然唯一!)
之后Hash表中查询,若查到(假设是j),则returni*m+j+d
否则
D=D*K%C,继续循环
(5)无条件返回-1;//无解!
下面是证明:
推论1:
A^x=B(modC)
等价为
A^a*A^b=B(modC)(a+b)==xa,b>=0
证明:
A^x=K*C+B(模的定义)
A^a*A^b=K*C+B(a,b>=0,a+b==x)
所以有
A^a*A^b=B(modC)
推论2:
令AA*A^b=B(modC)
那么解存在的必要条件为:可以得到至少一个可行解A^b=X(modC)
使上式成立
推论3
AA*A^b=B(modC)
中解的个数为(AA,C)
由推论3不难想到对原始BabyStepGiantStep的改进
ForI=0->m
ForanysolutionthatAA*X=B(modC)
IffindX
ReturnI*m+j
而根据推论3,以上算法的复杂度实际在(AA,C)很大的时候会退化到几乎O(C)
归结原因,是因为(AA,C)过大,而就是(A,C)过大
于是我们需要找到一中做法,可以将(A,C)减少,并不影响解
下面介绍一种“消因子”的做法
一开始D=1modC
进行若干论的消因子,对于每次消因子
令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'(modC')
于是可以得到算法
fori=0->m
解(D*(A^m)^i)*X=B'(modC')
由于(D*(A^m)^i,C')=1(想想为什么?)
于是我们可以得到唯一解
之后的做法就是对于这个唯一解在Hash中查找
这样我们可以得到b的值,那么最小解就是a'+b!!
现在问题大约已近解决了,可是细心看来,其实还是有BUG的,那就是
对于
A^x=B(modC)
如果x的最小解<a',那么会出错
而考虑到每次消因子最小消2
故a'最大值为log(C)
于是我们可以暴力枚举0->log(C)的解,若得到了一个解,直接返回
否则必然有解x>log(C)
PS.以上算法基于Hash表,如果使用map等平衡树维护,那么复杂度会更大
hdu2815
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#defineLLlonglong
#definenmax5000005
typedefstructnode{
intnum,ii;
}node;
nodeNode[nmax];
intx,y;
intcmp(constvoid*n,constvoid*m){
node*a=(node*)n;
node*b=(node*)m;
if(a->num==b->num){
if(a->ii>b->ii){
return1;
}
return-1;
}
if(a->num>b->num){
return1;
}
return-1;
}
intgcd(inta,intb){
intte;
if(a<b){
te=a,a=b,b=te;
}
if(b==0){
returna;
}
returngcd(b,a%b);
}
intext_gcd(inta,intb){
if(b==0){
x=1,y=0;
returna;
}
intd=ext_gcd(b,a%b);
inttx=x;
x=y,y=tx-a/b*y;
returnd;
}
intinval(inta,intb,intn){
inte;
ext_gcd(a,n);
e=(LL)x*b%n;
returne<0?e+n:e;
}
intmodular_exp(inta,intb,intc){
LLret=1%c,te=a%c;
while(b){
if(b&1){
ret=ret*te%c;
}
te=te*te%c;
b>>=1;
}
return(int)ret;
}
intbsearchn(intx,intn){
intleft,mid,right;
left=0,right=n+1;
while(left<=right){
mid=(left+right)/2;
if(Node[mid].num==x){
returnNode[mid].ii;
}elseif(Node[mid].num>x){
right=mid-1;
}else{
left=mid+1;
}
}
return-1;
}
intbaby_step_giant_step(inta,intb,intc){
inti,j,d,tep,m,K,tem,k;
LLD,buf;
for(i=0,buf=1%c,D=buf;i<100;i++,buf=buf*a%c){
if(buf==b){
returni;
}
}
d=0;
while((tep=gcd(a,c))!=1){
if(b%tep){
return-1;
}
++d;
c/=tep,b/=tep;
D=D*a/tep%c;
}
m=(int)(ceil(sqrt((double)c)));
for(i=0,buf=1%c;i<=m;i++,buf=buf*a%c){
Node[i].num=(int)buf;
Node[i].ii=i;
}
qsort(Node,m+1,sizeof(Node[0]),cmp);
for(i=0,j=0,k=-1;i<=m;i++){
if(k!=Node[i].num){
Node[j++]=Node[i];
k=Node[i].num;
}
}
m=j;
K=modular_exp(a,m,c);
for(i=0;i<=m;i++,D=D*K%c){
tem=inval((int)D,b,c);
if(tem>=0){
if((j=bsearchn(tem,m))!=-1){
returni*m+j+d;
}
}
}
return-1;
}
intmain(){
#ifndefONLINE_JUDGE
freopen("t.txt","r",stdin);
#endif
intk,p,n,res;
while(scanf("%d%d%d",&k,&p,&n)!=EOF){
if(n>=p){
puts("Orz,Ican’tfindD!");
continue;
}
res=baby_step_giant_step(k,n,p);
if(res==-1){
puts("Orz,Ican’tfindD!");
continue;
}
printf("%d\n",res);
}
return0;
}
最新版~!
pku3243
【普通BabyStepGiantStep】
【问题模型】
求解
A^x=B(modC)中0<=x<C的解,C为素数
【思路】
我们可以做一个等价
x=i*m+j(0<=i<m,0<=j<m)m=Ceil(sqrt(C))
而这么分解的目的无非是为了转化为:
(A^i)^m*A^j=B(modC)
之后做少许暴力的工作就可以解决问题:
(1)fori=0->m,插入Hash(i,A^imodC)
(2)枚举i,对于每一个枚举到的i,令AA=(A^m)^imodC
我们有
AA*A^j=B(modC)
显然AA,B,C均已知,而由于C为素数,那么(AA,C)无条件为1
于是对于这个模方程解的个数唯一(可以利用扩展欧几里得或欧拉定理来求解)
那么对于得到的唯一解X,在Hash表中寻找,如果找到,则返回i*m+j
注意:由于i从小到大的枚举,而Hash表中存在的j必然是对于某个剩余系内的元素X是最小的(就是指标)
所以显然此时就可以得到最小解
如果需要得到x>0的解,那么只需要在上面的步骤中判断当i*m+j>0的时候才返回
到目前为止,以上的算法都不存在争议,大家实现的代码均相差不大。可见当C为素数的时候,此类离散对数的问题可以变得十分容易实现。
【扩展BabyStepGiantStep】
【问题模型】
求解
A^x=B(modC)中0<=x<C的解,C无限制(当然大小有限制……)
【写在前面】
这个问题比较麻烦,目前网络上流传许多版本的做法,不过大部分已近被证明是完全错误的!
这里就不再累述这些做法,下面是我的做法(有问题欢迎提出)
下面先给出算法框架,稍后给出详细证明:
(0)fori=0->50if(A^imodC==B)returniO(50)
(1)d<-0D<-1modC
while((tmp=gcd(A,C))!=1)
{
if(B%tmp)return-1;//无解!
++d;
C/=tmp;
B/=tmp;
D=D*A/tmp%C;
}
(2)m=Ceil(sqrt(C))//Ceil是必要的O(1)
(3)fori=0->m插入Hash表(i,A^imodC)O(m)
(4)K=pow_mod(A,m,C)
fori=0->m
解D*X=B(modC)的唯一解(如果存在解,必然唯一!)
之后Hash表中查询,若查到(假设是j),则returni*m+j+d
否则
D=D*K%C,继续循环
(5)无条件返回-1;//无解!
下面是证明:
推论1:
A^x=B(modC)
等价为
A^a*A^b=B(modC)(a+b)==xa,b>=0
证明:
A^x=K*C+B(模的定义)
A^a*A^b=K*C+B(a,b>=0,a+b==x)
所以有
A^a*A^b=B(modC)
推论2:
令AA*A^b=B(modC)
那么解存在的必要条件为:可以得到至少一个可行解A^b=X(modC)
使上式成立
推论3
AA*A^b=B(modC)
中解的个数为(AA,C)
由推论3不难想到对原始BabyStepGiantStep的改进
ForI=0->m
ForanysolutionthatAA*X=B(modC)
IffindX
ReturnI*m+j
而根据推论3,以上算法的复杂度实际在(AA,C)很大的时候会退化到几乎O(C)
归结原因,是因为(AA,C)过大,而就是(A,C)过大
于是我们需要找到一中做法,可以将(A,C)减少,并不影响解
下面介绍一种“消因子”的做法
一开始D=1modC
进行若干论的消因子,对于每次消因子
令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'(modC')
于是可以得到算法
fori=0->m
解(D*(A^m)^i)*X=B'(modC')
由于(D*(A^m)^i,C')=1(想想为什么?)
于是我们可以得到唯一解
之后的做法就是对于这个唯一解在Hash中查找
这样我们可以得到b的值,那么最小解就是a'+b!!
现在问题大约已近解决了,可是细心看来,其实还是有BUG的,那就是
对于
A^x=B(modC)
如果x的最小解<a',那么会出错
而考虑到每次消因子最小消2
故a'最大值为log(C)
于是我们可以暴力枚举0->log(C)的解,若得到了一个解,直接返回
否则必然有解x>log(C)
PS.以上算法基于Hash表,如果使用map等平衡树维护,那么复杂度会更大
hdu2815
最新版~!
/* a^x=b(modc) */ #include<stdio.h> #include<math.h> #include<stdlib.h> #defineLLlonglong #definennum100 #definenmax31625 typedefstructnum{ intii,value; }num; numNum[nmax]; intx,y; intcmp(constvoid*a,constvoid*b){ numn=*(num*)a; numm=*(num*)b; returnn.value-m.value; } intgcd(inta,intb){ returnb==0?a:gcd(b,a%b); } voidextend_gcd(inta,intb){ intxx; if(b==0){ x=1,y=0; return; } extend_gcd(b,a%b); xx=x; x=y,y=xx-a/b*y; } /* ax=b(modn) */ intinval(inta,intb,intn){ LLres; extend_gcd(a,n); res=(LL)x; res=res*b; res=(res%n+n)%n; return(int)res; } intbfindNum(intkey,intn){ intleft,right,mid; left=0,right=n; while(left<=right){ mid=(left+right)>>1; if(Num[mid].value==key){ returnNum[mid].ii; }elseif(Num[mid].value>key){ right=mid-1; }else{ left=mid+1; } } return-1; } voidbaby_step_giant_step(inta,intb,intc){ inti,j,te,d,cd,aa,ttemp; LLtemp,tem; if(b>=c){ puts("Orz,Ican’tfindD!"); return; } for(i=0,temp=1%c,tem=temp;i<nnum;i++,temp=temp*a%c){ if(temp==b){ printf("%d\n",i); return; } } cd=0; while((d=gcd(a,c))!=1){ if(b%d){ puts("Orz,Ican’tfindD!"); return; } cd++; c/=d,b/=d; tem=tem*a/d%c; } te=(int)(sqrt(c*1.0)+0.5); for(i=0,temp=1%c;i<=te;i++,temp=temp*a%c){ Num[i].ii=i; Num[i].value=(int)temp; } aa=Num[te].value; qsort(Num,te+1,sizeof(Num[0]),cmp); for(i=0;i<=te;i++,tem=tem*aa%c){ ttemp=inval(tem,b,c); if(ttemp>=0){ j=bfindNum(ttemp,te+1); if(j!=-1){ printf("%d\n",i*te+j+cd); return; } } } puts("Orz,Ican’tfindD!"); } voidsolve(inta,intb,intc){ baby_step_giant_step(a,b,c); } intmain(){ #ifndefONLINE_JUDGE freopen("data.in","r",stdin); #endif intk,p,n; while(~scanf("%d%d%d",&k,&p,&n)){ solve(k,n,p); } return0; }
pku3243
/* a^x=b(modc) */ #include<stdio.h> #include<math.h> #include<stdlib.h> #defineLLlonglong #definennum100 #definenmax31625 typedefstructnum{ intii,value; }num; numNum[nmax]; intx,y; intcmp(constvoid*a,constvoid*b){ numn=*(num*)a; numm=*(num*)b; returnn.value-m.value; } intgcd(inta,intb){ returnb==0?a:gcd(b,a%b); } voidextend_gcd(inta,intb){ intxx; if(b==0){ x=1,y=0; return; } extend_gcd(b,a%b); xx=x; x=y,y=xx-a/b*y; } /* ax=b(modn) */ intinval(inta,intb,intn){ LLres; extend_gcd(a,n); res=(LL)x; res=res*b; res=(res%n+n)%n; return(int)res; } intbfindNum(intkey,intn){ intleft,right,mid; left=0,right=n; while(left<=right){ mid=(left+right)>>1; if(Num[mid].value==key){ returnNum[mid].ii; }elseif(Num[mid].value>key){ right=mid-1; }else{ left=mid+1; } } return-1; } voidbaby_step_giant_step(inta,intb,intc){ inti,j,te,d,cd,aa,ttemp; LLtemp,tem; for(i=0,temp=1%c,tem=temp;i<nnum;i++,temp=temp*a%c){ if(temp==b){ printf("%d\n",i); return; } } cd=0; while((d=gcd(a,c))!=1){ if(b%d){ puts("NoSolution"); return; } cd++; c/=d,b/=d; tem=tem*a/d%c; } te=(int)(sqrt(c*1.0)+0.5); for(i=0,temp=1%c;i<=te;i++,temp=temp*a%c){ Num[i].ii=i; Num[i].value=(int)temp; } aa=Num[te].value; qsort(Num,te+1,sizeof(Num[0]),cmp); for(i=0;i<=te;i++,tem=tem*aa%c){ ttemp=inval(tem,b,c); if(ttemp>=0){ j=bfindNum(ttemp,te+1); if(j!=-1){ printf("%d\n",i*te+j+cd); return; } } } puts("NoSolution"); } voidsolve(inta,intb,intc){ baby_step_giant_step(a,b,c); } intmain(){ #ifndefONLINE_JUDGE freopen("data.in","r",stdin); #endif intx,z,k; while(~scanf("%d%d%d",&x,&z,&k)&&(x||z||k)){ solve(x,k%z,z); } return0; }
相关文章推荐
- Hdu 2815 Mod Tree + Poj 3243 Clever Y 扩展Baby Step Giant Step 解决离散对数问题
- hdu 2815 Mod Tree 模方程a^x=b(mod n),n为任意正整数+模板题(扩展Baby Step Giant Step)
- POJ 3243 Clever Y (求解高次同余方程A^x=B(mod C) Baby Step Giant Step算法)
- 高次同余方程:poj 3243+poj 2417+hdu 2815 (Baby Step Giant Step 算法)
- poj 3243 Clever Y&&hdu 2815 Mod Tree(扩展baby_step)
- hdu 2815 Mod Tree (数论题)(baby step giant step 小步大步)
- POJ 3243 Clever Y Extended-Baby-Step-Giant-Step
- HDU 2815 Mod Tree 离散对数 扩张Baby Step Giant Step算法
- POJ 3243 Clever Y Extended-Baby-Step-Giant-Step
- HDU 2815 扩展baby step giant step 算法
- hdu——2815(数论之Baby Step Giant Step解决离散对数问题)
- HDU 2815 Mod Tree 离散对数 扩展Baby Step Giant Step算法
- POJ 3243 Clever Y 求A^X = B (mod C) / BabyStep_GiantStep
- HDU 2815 Mod Tree【扩展Baby Step Giant Step解决离散对数问题】
- pku3243(baby_step, giant_step算法)
- POJ 3243: Clever Y 求A^X = B (mod C) / BabyStep_GiantStep
- HDU 2815 Mod Tree (扩展 Baby Step Giant Step )
- [zz]hdu 2815——Mod Tree【扩展Baby Step Giant Step解决离散对数问题】
- poj 3243 Clever Y(Baby-Step Giant-Step)
- hdu 2815 Mod Tree pku 3243 Clever Y