Discrete Logging hunnu10590 pku2417 fzu 1352 hit 1928 zoj 1898

以下转自:http://hi.baidu.com/aekdycoin/blog/item/b317ca18bb24334942a9ad55.html

【普通Baby Step Giant Step】

【问题模型】
求解
A^x = B (mod C) 中 0 <= x < C 的解,C 为素数

【思路】
我们可以做一个等价
x = i * m + j  ( 0 <= i < m, 0 <=j < m) m = Ceil ( sqrt( C) )
而这么分解的目的无非是为了转化为:
(A^i)^m * A^j = B ( mod C)

之后做少许暴力的工作就可以解决问题:
(1) for i = 0 -> m, 插入Hash (i, A^i mod C)
(2) 枚举 i ,对于每一个枚举到的i,令  AA = (A^m)^i mod C
我们有
AA * A^j = B (mod C)
显然AA,B,C均已知,而由于C为素数,那么(AA,C)无条件为1
于是对于这个模方程解的个数唯一(可以利用扩展欧几里得欧拉定理来求解)
那么对于得到的唯一解X,在Hash表中寻找,如果找到,则返回 i * m + j
注意:由于i从小到大的枚举,而Hash表中存在的j必然是对于某个剩余系内的元素X 是最小的(就是指标)
所以显然此时就可以得到最小解


如果需要得到 x > 0的解,那么只需要在上面的步骤中判断 当 i * m + j > 0 的时候才返回


到目前为止,以上的算法都不存在争议,大家实现的代码均相差不大。可见当C为素数的时候,此类离散对数的问题可以变得十分容易实现。

#include<stdio.h>

#include<math.h>

#include<stdlib.h>

#define nmax 46341

#define LL long long

typedef struct Num {

	int nnum;

	int ii;

} Num;

Num num[nmax];

int x, y;

int cmp(const void *a, const void *b) {

	Num *n = (Num *) a;

	Num *m = (Num *) b;

	if (n->nnum > m->nnum) {

		return 1;

	}

	return -1;

}

int extend_gcd(int a, int b) {

	if (b == 0) {

		x = 1, y = 0;

		return a;

	}

	int d = extend_gcd(b, a % b);

	int tx = x;

	x = y;

	y = tx - a / b * y;

	return d;

}

int find_num(int x, int n) {

	int mid, left, right;

	left = 0, right = n + 1;

	while (left <= right) {

		mid = (left + right) >> 1;

		if (num[mid].nnum == x) {

			return num[mid].ii;

		} else if (num[mid].nnum > x) {

			right = mid - 1;

		} else {

			left = mid + 1;

		}

	}

	return -1;

}

int main() {

#ifndef ONLINE_JUDGE

	freopen("t.txt", "r", stdin);

	freopen("out.txt", "w", stdout);

#endif

	LL ptemp, te;

	int i, j, pte, p, b, n, bb, temp;

	while (scanf("%d %d %d", &p, &b, &n) != EOF) {

		pte = (int) ((sqrt(p * 1.0) + 0.5));

		for (i = 0, ptemp = 1; i <= pte; i++) {

			num[i].nnum = (int) (ptemp);

			num[i].ii = i;

			ptemp = ptemp * b % p;

		}

		bb = num[pte].nnum;

		qsort(num, pte + 1, sizeof(num[0]), cmp);

		for (i = 0, ptemp = 1; i <= pte; i++) {

			temp = (int) (ptemp);

			extend_gcd(temp, p);

			te = (int) (x);

			te = te * n;

			te = te % p + p;

			x = (int) (te % p);

			j = find_num(x, pte);

			if (j != -1) {

				printf("%d\n", pte * i + j);

				break;

			}

			ptemp = ptemp * bb % p;



		}

		if (i > pte) {

			printf("ERROR\n");

		}

	}

	return 0;

}

 
 
 hunnu 10590 fzu 1352 pku 2417 hit 1928 zoj 1898
 
/*
a^x=b (mod c) c is prime
*/
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<stdlib.h>
#define LL long long
#define nmax 46345
typedef struct num {
int ii, value;
} num;
num Num[nmax];
int x, y;
int cmp(const void *a, const void *b) {
num n = *(num *) a;
num m = *(num *) b;
return n.value - m.value;
}
void extend_gcd(int a, int b) {
int xx;
if (b == 0) {
x = 1, y = 0;
return;
}
extend_gcd(b, a % b);
xx = x;
x = y, y = xx - a / b * y;
}
int bfindNum(int key, int n) {
int left, right, mid;
left = 0, right = n;
while (left <= right) {
mid = (left + right) >> 1;
if (Num[mid].value == key) {
return Num[mid].ii;
} else if (Num[mid].value > key) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return -1;
}
void solve(int c, int a, int b) {
int i, j, te, aa;
LL temp, xx;
te = (int) (sqrt(c * 1.0) + 0.5);
for (i = 0, temp = 1 % c; i <= te; i++) {
Num[i].ii = i;
Num[i].value = (int) (temp);
temp = temp * a % c;
}
aa = Num[te].value;
qsort(Num, te + 1, sizeof(Num[0]), cmp);
for (i = 0, temp = 1; i <= te; i++) {
extend_gcd((int) (temp), c);
xx = (LL) x;
xx = xx * b;
xx = xx % c + c;
x = (int) (xx % c);
j = bfindNum(x, te + 1);
if (j != -1) {
printf("%d\n", i * te + j);
return;
}
temp = temp * aa % c;
}
puts("no solution");
}
int main() {
#ifndef ONLINE_JUDGE
freopen("data.in", "r", stdin);
#endif
int p, b, n;
while (~scanf("%d %d %d", &p, &b, &n)) {
solve(p, b, n);
}
return 0;
}

你可能感兴趣的:(logging)