fzu 1493 小步大步攻击算法

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

题目http://acm.fzu.edu.cn/problem.php?pid=1493

题目大意a^x = b (mod c) 已知abc,x a,bx < c  c <2^31 , c 是素数。)

考点:小步大步攻击算法。

思路要在[0,c]内求x,只能枚举,但是暴力的枚举肯定会超时,于是我们做一个等价的替换, 下面是过程

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

Step 1 m = ceil(sqrt(c));

Step 2 :等价替换  x = i * m + j其中(0 < i , j <m

              A ^ x 等价于  A^i^m * A^j

         即:a ^(i*m) * a^j = b (mod c)

Step 3 j = 0 -> m (j,  a^j mod c)HASH

Step 4 i = 0 -> m temp = a ^ m ^ i mod c

          那么a ^(i*m) * a^j = b (mod c)就变成了

              temp * a^j= b (mod c)  再令y = a ^j式子变成了

              temp * y = b (modc)

其中tempb, c都是已知的,可利用扩展欧几里德求解y

HASH表中查找y是否存在,若存在则x = i * m + HASH(y). j

Step 5 :若查找到了y这有解, 若查找不到, 则无解

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

上面做的等价替换,目的是把O(n)的时间复杂度降低到O(fzu <wbr>1493 <wbr>小步大步攻击算法).使得枚举的长度减少了一半

提交情况time limit error 10  原因 HASH是没有递推,导致超时

                    Accepted 2

收获:了解个小步大步攻击算法的思路,学会了按位与的hash方法(和取模时间一样)

经验不能盲目编码,注意一些可以优化的地方。要理解每个过程的原理

 

AC code

#include <stdio.h>

#include <math.h>

#include <string.h>

 

#define MAXN 65535

#define I64 __int64

 

struct LINK{

   I64 data, j;

   I64 next;

}HASH_LINK[MAXN];

 

I64 head[MAXN], ad;

 

void clear(){

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

   ad = 0;

}

 

I64 hash(I64 n){

   return n % MAXN;

}

 

void insert(I64 j, I64 data){

   for(I64 i = head[hash(data)]; ~i; i= HASH_LINK[i]. next)

      if(HASH_LINK[i]. data == data)return;

   HASH_LINK[ad]. data = data;

   HASH_LINK[ad]. j   = j;

   HASH_LINK[ad]. next = head[hash(data)];

   head[hash(data)] = ad ++;

}

 

I64 POWER_MOD(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;

}

 

I64 Ext_Gcd(I64 a, 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 babystep_giantstep(I64 a, I64 b, I64c){

   I64 m = (I64)ceil(sqrt((longdouble)c ));

   I64 i, tem, x, y;

   clear();

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

   tem = POWER_MOD(a, m, c);

   for(i = 0; i <= m; i++){

      I64 ans = POWER_MOD(tem, i, c);

      Ext_Gcd(ans, c, x, y);

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

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

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

   }

   return -1;

}

 

int main(){

   I64 a, b, c, ans;

   while(~scanf("%I64d %I64d %I64d", &c,&a, &b)){

      ans = babystep_giantstep(a, b, c);

      ans == -1 ? printf("ERROR\n") :printf("%I64d\n",ans);

   }

   return 0;

}

原创粉丝点击