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;
}
题目大意: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;
}
相关文章推荐
- 大步小步攻击算法_完全版
- 大步小步攻击算法_完全版
- 大步小步算法(BSGS)及扩展 & bzoj 2480
- POJ 2417 大步小步算法
- TCP&nbsp;Nagle&#039;s&nbsp;&nbsp;算法导致的性能问题
- 5.4 优化算法与利益最大化
- ACM: 匈牙利算法 图论题 poj 3041 …
- 调整 TCP/IP 防范攻击
- Union-Find 按大小求并算法
- VTK教程之八&nbsp;可视化基础算法-颜色…
- 【原创】【算法】python 选择排序
- POJ 2417 Discrete Logging(离散对数-小步大步算法)
- POJ 3243 Clever Y(离散对数-拓展小步大步算法)
- BSGS算法(大步小步算法)
- uva 11916 大步小步算法
- Top&nbsp;K算法详细解析
- K-Means&nbsp;算法的应用
- 算法分析之Paxos 算法
- 匈牙利算法&nbsp;找舞娘
- 从头到尾彻底解析Hash&nbsp;表算法