hdu2815扩展小步大步攻击

来源:互联网 发布:毒品网络 百度云 编辑:程序博客网 时间:2024/05/18 00:25

题目 http://acm.hdu.edu.cn/showproblem.php?pid=2815

题目大意 求解 a ^ x = b ( mod c) (0 < a, b, c < 10^9)

算法 扩展小步大步攻击(AC大牛)

思路 :在介绍扩展小步大步攻击之前, 先说两个要点

1 :如 d = a % b, Gcd(a, b) | d;

证明 d = a % b = a – a / b * b = ged(a, b)[a / gcd(a, b)  - a / b * b / gcd(a, b)]

2 :消因子

对于 a ^ x = b ( mod c)

可写成 a^ x = k * c + b

g1 = gcd(a, c), 若有解着必有 g1 | b

方程两边同时消去g a/g1 * a ^ (x-1) = k * c’ + b’ (消了一次因子的结果)

再设g2 = gcd(a, c’), 同理,若有解, g2 | b’

方程两边同时消去g a/g2 * a/g1 * a ^ (x-2) = k * c’’ + b’’ (消了两次次因子的结果)

同样的操作, 假设第n次后a,c不具有因子,a, c’’’’’’’ 互素时

则有 a/g(n) * a/g(n-1)……*a/g1 * a^(x – n) = b’’’’’(n) (modc’’’’’(n))

d = a/g(n) *a/g(n-1)……*a/g1,

 B = b’’’’’(n)

 C = c’’’’’(n)

则有 d * a (x - n) = B (modC);

这样, a C 就是互素的了

//////////////////////////////////////////////////////////////////////////////////////

扩展小步大步攻击:a ^ x = b (mod c)

1   i = 0-> 100 if a^i mod c == b return i

2   消因子, a^x = b mod c 划为 d * a ^ (x – n) = B (modC)

3 m = ceil (sqrt(C))

4 a ^ (x - n) 化为  a ^ (I * m + j)(x 化为了 n + I * m + j)这里与小步大步攻击不同

5 for j = 0 ->m   hashj,a ^ j mod c

6 for i = 0 ->m   AA = d * a ^ m ^i

7 AA * x = B (mod C)ext_gcd求解x,判断hash中是否有x若有,则答案为I * m + j + n

/////////////////////////////////////////////////////////////////////////////////////////////////

消因子的目的在于将AAC化为互素的关系,这样用ext_gcd求的x时就只有唯一解了。

而消因子后, 我们的解最小为n,如果小于n有解,则会出现错误, 故有了第一步的操作,先看n以前是否有满足的解,100就足够了

//介意与ac大牛原著一起看http://hi.baidu.com/aekdycoin/blog/item/b317ca18bb24334942a9ad55.html

提交情况 runtime error 5   gcd写错了hdu2815扩展小步大步攻击

          Wrong answer 3   +   写成了 =居然样例没错,,,,,,,,,hdu2815扩展小步大步攻击

                     Accepted 1

 

感想和经验颇多, 都在思路理了

AC code

 

#include<stdio.h>

#include<string.h>

#include<math.h>

 

#defineMAXN65536

#defineI64 __int64

 

structLINK{

   I64 data;

   I64 j;

   I64 next;

}HASH_LINK[1000000];

I64 ad,head[MAXN];

 

I64 Gcd(I64 a,I64 b){

return b ? Gcd(b, a % b) :a;

}

 

I64 Ext_Gcd(I64a, I64 b, I64 &x, I64&y){

   if(!b){

      x = 1; y = 0;

      return a;

   }

   I64 r = Ext_Gcd(b, a % b, x, y);

   I64 t = x; x = y; y = t - a / b * y;

   return r;

}

 

I64 POWER(I64 a,I64 b, I64 c){

   I64 ans = 1;

   while(b){

      if(b & 1) ans = ans* a % c;

      a = a * a % c;

      b >>= 1;

   }

   return ans;

}

 

voidclear(){

   memset(head, -1, sizeof(head));

   ad = 0;

}

 

I64 hash(I64a){

   return a % MAXN;

}

 

voidINSERT_HASH(I64 i,I64 buf){

   I64 hs = hash(buf), tail;

   for(tail = head[hs]; ~tail; tail =HASH_LINK[tail]. next)

      if(buf == HASH_LINK[tail]. data)return;

   HASH_LINK[ad]. data = buf;

   HASH_LINK[ad].j    =i;

   HASH_LINK[ad]. next = head[hs];

   head[hs] = ad ++;

}

 

I64bady_step_giant_step(I64 a, I64 b, I64 c){

   I64 i, buf, m, temp, g, D, x, y, n = 0;

   for(i = 0, buf = 1; i< 100; i ++, buf = buf * a % c)

      if(buf == b) return i;

   D = 1;

   while((g = Gcd(a, c)) !=1){

      if(b % g) return-1;// g | b 不满足,则说明无解

      b /= g;

      c /= g;hdu2815扩展小步大步攻击

      D = D * a / g % c;

      ++ n;

   }

   clear();

   m = ceil(sqrt((long double) c));

   for(i = 0, buf = 1; i<= m; buf = buf * a % c, i ++) INSERT_HASH(i,buf);

   for(i = 0, temp = POWER(a, m, c),buf = D; i <= m; i ++, buf = temp * buf %c){

      Ext_Gcd(buf, c, x, y);

      x = ((x * b) % c + c) % c;

      for(I64 tail = head[hash(x)];~tail; tail = HASH_LINK[tail].next)

          if(HASH_LINK[tail]. data == x)return HASH_LINK[tail].j + n + i *m;

   }

   return -1;

}

 

intmain(){

   I64 k, p, n, ans;

   while(~scanf("%I64d %I64d %I64d", &k,&p, &n)){

      if(n >= p){printf("Orz,I can’¡¥t findD!\n"); continue;}

      ans = bady_step_giant_step(k, n, p);

      ans == -1 ? printf("Orz,I can’¡¥t findD!\n") : printf("%I64d\n", ans);

   }

   return 0;

}