fzu 1493 小步大步攻击算法

题目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 (mod c)

其中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, I64 c){

    I64 m = (I64)ceil(sqrt((long double)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;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值