设为首页 加入收藏

TOP

HDU 2815 Mod Tree 离散对数 扩展Baby Step Giant Step算法
2015-07-20 17:59:53 来源: 作者: 【 】 浏览:2
Tags:HDU 2815 Mod Tree 离散 对数 扩展 Baby Step Giant 算法

?

题意:\

思路:与上题不同,这道题不要求m是素数,是利用扩展Baby Step Giant Step算法求离散对数。

以下转载自:AekdyCoin

【扩展Baby Step Giant Step】

【问题模型】
求解
A^x = B (mod C) 中 0 <= x < C 的解,C 无限制(当然大小有限制……)

【写在前面】
这个问题比较麻烦,目前网络上流传许多版本的做法,不过大部分已近被证明是完全错误的!

这里就不再累述这些做法,下面是我的做法(有问题欢迎提出)

下面先给出算法框架,稍后给出详细证明:

(0) for i = 0 -> 50 if(A^i mod C == B) return i O(50)
(1) d<- 0 D<- 1 mod C
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) for i = 0 -> m 插入Hash表(i, A^i mod C) O( m)
(4) K=pow_mod(A,m,C)
for i = 0 -> m
解 D * X = B (mod C) 的唯一解 (如果存在解,必然唯一!)
之后Hash表中查询,若查到(假设是 j),则 return i * m + j + d
否则
D=D*K%C,继续循环
(5) 无条件返回 -1 ;//无解!


下面是证明:
推论1:
A^x = B(mod C)
等价为
A^a * A^b = B ( mod C) (a+b) == x a,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(mod C)

推论 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等平衡树维护,那么复杂度会更大

(转载结束)

代码:

?

#include 
  
   
#include 
   
     #include 
    
      #include 
     
       #include
       #include 
       
         #include 
        
          #include 
         
           #include 
          
            #include 
           
             #include 
            
              #include 
             
               #include 
              
                #define PI acos(-1.0) #define maxn 1000005 #define INF 0x7fffffff #define eps 1e-8 typedef long long LL; typedef unsigned long long ULL; using namespace std; int extend_gcd(int a, int b, int &x, int &y) { if(b==0) { x=1; y=0; return a; } int r=extend_gcd(b,a%b,x,y); int t=x; x=y; y=t-a/b*y; return r; } LL pow_mod(LL aa,LL ii,LL nn) { if(ii==0) return 1%nn; LL temp=pow_mod(aa,ii>>1,nn); temp=temp*temp%nn; if(ii&1) temp=temp*aa%nn; return temp; } struct b_step { int i,m; } bb[maxn]; int inval(int a,int b,int n) { int e,x,y; extend_gcd(a,n,x,y); e=((LL)x*b)%n; return e<0?e+n:e; } bool cmp(b_step a,b_step b) { return a.m==b.m?a.i
               
                >1; if(bb[mid].m==num) return bb[mid].i; if(bb[mid].m
                
                 =0) { int pos=BiSearch(top,tmp); if(pos!=-1) return i*m+pos+d; } D=((LL)(D*bm))%p; } return -1; } int main() { int b,p,n; while(~scanf(%d%d%d,&b,&p,&n)) { if(n>=p) { puts(Orz,I can’t find D!); continue; } int ans=giant_step_baby_step(b,n,p); if(ans==-1) puts(Orz,I can’t find D!); else printf(%d ,ans); } return 0; } 
                
               
              
             
            
           
          
         
        
       
     
    
   
  


?

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇ListView中pointToPosition()方法.. 下一篇hdu 4908 BestCoder Sequence(计..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: