• 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;
    }

  • 相关阅读:
    [转载]辗转相除法
    [转载]自由不是什么
    [翻译]与比尔·盖茨面对面
    [翻译]AJAX XMLHttpRequest对象 详解
    [转载]Win32应用程序中进程间通信方法分析与比较
    C# 中的类型转换
    Log4Net
    抽象类和接口
    有用的自定义pagecounter控件
    单点登陆单web应用的单点登陆
  • 原文地址:https://www.cnblogs.com/xiaoxian1369/p/2127447.html
Copyright © 2020-2023  润新知