hdu 2815 Mod Tree (数论题)(baby step giant step 小步大步)
2013-07-10 14:44
531 查看
这题的解法是参考福州大学的数论大神 AekdyCoin 的。
用消元法,并附上ac大神的证明
原创帖!转载请注明作者 AekdyCoin !
【普通Baby Step Giant Step】
【问题模型】
求解
A^x = B (mod C) 中 0 <= x < C 的解,C 为素数
【思路】
我们可以做一个等价
x = i * m + j ( 0 <= i < m, 0 <=j < m) m = Ceil ( sqrt( C) )
而这么分解的目的无非是为了转化为:
(A^i)^m * A^j = B ( mod C)
之后做少许暴力的工作就可以解决问题:
(1) for i = 0 -> m, 插入Hash (i, A^i mod C)
(2) 枚举 i ,对于每一个枚举到的i,令 AA = (A^m)^i mod C
我们有
AA * A^j = B (mod C)
显然AA,B,C均已知,而由于C为素数,那么(AA,C)无条件为1
于是对于这个模方程解的个数唯一(可以利用扩展欧几里得或 欧拉定理来求解)
那么对于得到的唯一解X,在Hash表中寻找,如果找到,则返回 i * m + j
注意:由于i从小到大的枚举,而Hash表中存在的j必然是对于某个剩余系内的元素X 是最小的(就是指标)
所以显然此时就可以得到最小解
如果需要得到 x > 0的解,那么只需要在上面的步骤中判断 当 i * m + j > 0 的时候才返回
【扩展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;
}
ps:这里用到了这个公式:设g=(a,c),当g|b时,ax=b(mod c)等价于(a/g)x=(b/g)(mod (c/g))
(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 ;//无解!
下面是证明:
推论
AA * A^b = B(mod C)
中解的个数为 (AA,C)
由推论 不难想到对原始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)
用消元法,并附上ac大神的证明
【扩展Baby Step Giant Step解决离散对数问题】
原创帖!转载请注明作者 AekdyCoin !【普通Baby Step Giant Step】
【问题模型】
求解
A^x = B (mod C) 中 0 <= x < C 的解,C 为素数
【思路】
我们可以做一个等价
x = i * m + j ( 0 <= i < m, 0 <=j < m) m = Ceil ( sqrt( C) )
而这么分解的目的无非是为了转化为:
(A^i)^m * A^j = B ( mod C)
之后做少许暴力的工作就可以解决问题:
(1) for i = 0 -> m, 插入Hash (i, A^i mod C)
(2) 枚举 i ,对于每一个枚举到的i,令 AA = (A^m)^i mod C
我们有
AA * A^j = B (mod C)
显然AA,B,C均已知,而由于C为素数,那么(AA,C)无条件为1
于是对于这个模方程解的个数唯一(可以利用扩展欧几里得或 欧拉定理来求解)
那么对于得到的唯一解X,在Hash表中寻找,如果找到,则返回 i * m + j
注意:由于i从小到大的枚举,而Hash表中存在的j必然是对于某个剩余系内的元素X 是最小的(就是指标)
所以显然此时就可以得到最小解
如果需要得到 x > 0的解,那么只需要在上面的步骤中判断 当 i * m + j > 0 的时候才返回
【扩展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;
}
ps:这里用到了这个公式:设g=(a,c),当g|b时,ax=b(mod c)等价于(a/g)x=(b/g)(mod (c/g))
(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 ;//无解!
下面是证明:
推论
AA * A^b = B(mod C)
中解的个数为 (AA,C)
由推论 不难想到对原始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)
#include<stdio.h> #include<math.h> #include<map> using namespace std; map<long long,long long>ff; long long A,P,N; long long gcd(long long a,long long b) { if(b==0)return a; return gcd(b,a%b); } long long extEuclid(long long a,long long b,long long &x,long long &y)//欧几里得算法 { long long d,tmp; if(b==0){x=1;y=0;return a;} d=extEuclid(b,a%b,x,y); tmp=x;x=y;y=tmp-a/b*y; return d; } int main() { long long i,j,k,D; while(scanf("%I64d%d%d",&A,&P,&N)!=-1) { if(N>=P) { printf("Orz,I can’t find D!\n"); continue; } if(N==1) { printf("0\n"); continue; } long long tmp=1; for(i=1;i<50;i++) { tmp=tmp*A%P; if(tmp==N) break; } if(i<50) { printf("%I64d\n",i); continue; } long long d=0,D=1; while((tmp=gcd(A,P))!=1) { if(N%tmp)break; d++; P/=tmp; N/=tmp; D=D*A/tmp%P; } if(tmp>1) { printf("Orz,I can’t find D!\n"); continue; } long long m=ceil(sqrt(P)); ff.clear(); tmp=1; ff[1]=0; for(i=1;i<=m;i++) { tmp=tmp*A%P; if(ff.find(tmp)==ff.end()) ff[tmp]=i; } long long k=tmp,x,y,ans=-1; for(i=0;i<=m;i++) { extEuclid(D,P,x,y); x=(x*N%P+P)%P; if(ff.find(x)!=ff.end()) { ans=i*m+ff[x]+d; break; } D=D*k%P; } if(ans!=-1) printf("%I64d\n",ans); else printf("Orz,I can’t find D!\n"); } return 0; }
相关文章推荐
- HDU 2815 Mod Tree (扩展 Baby Step Giant Step )
- HDU 2815 Mod Tree 离散对数 扩张Baby Step Giant Step算法
- 数论——Baby Step Giant Step大步小步算法
- 恶补数论(二) Baby-Step-Giant-Step 大步小步求离散模对数
- HDU 2815 Mod Tree 离散对数 扩展Baby Step Giant Step算法
- HDU 2815 Mod Tree【扩展Baby Step Giant Step解决离散对数问题】
- hdu——2815(数论之Baby Step Giant Step解决离散对数问题)
- [zz]hdu 2815——Mod Tree【扩展Baby Step Giant Step解决离散对数问题】
- 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)
- HDU 2815 扩展baby step giant step 算法
- POJ 2417 baby_step giant_step 小步大步算法 a^x == b(mod n) 求解0<=x<n的值
- 高次同余方程:poj 3243+poj 2417+hdu 2815 (Baby Step Giant Step 算法)
- baby_step giant_step hdu 2815 mod tree pku 3243 Clever Y
- poj 3243 Clever Y&&hdu 2815 Mod Tree(扩展baby_step)
- hdu 2815 大步小步
- 【模板】Big-Step-Giant-Step 大步小步
- poj 2417 Discrete Logging 数论baby_step,giant_step算法
- hdu 2815 baby-step
- hdu 2815 baby-step