hdu2815扩展小步大步攻击

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

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

 B = b’’’’’(n)

 C = c’’’’’(n)

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

这样, 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 (mod C)

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>

 

#define MAXN 65536

#define I64 __int64

 

struct LINK{

    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(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 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(I64 a){

    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 ++;

}

 

I64 bady_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;

}

 

int main(){

    I64 k, p, n, ans;

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

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

       ans = bady_step_giant_step(k, n, p);

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

    }

    return 0;

}

 

 

 

        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值