您的位置:首页 > 其它

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; }

最新版~!

/*
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;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: