您的位置:首页 > 其它

fzu 1493 小步大步攻击算法

2013-11-18 16:00 253 查看
题目:http://acm.fzu.edu.cn/problem.php?pid=1493

题目大意:a^x = b (mod c)
已知abc,求x
( a,b,x < 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)

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

在HASH表中查找y是否存在,

若存在则x = i * m + HASH(y). j
Step 5
:若查找到了y,

这有解,
若查找不到,
则无解

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

上面做的等价替换,目的是把O(n)的时间复杂度降低到O(


1493 小步大步攻击算法" TITLE="fzu 1493 小步大步攻击算法" />
).使得枚举的长度减少了一半

提交情况: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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: