zoukankan      html  css  js  c++  java
  • 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;
    }

  • 相关阅读:
    JavaScript对原始数据类型的拆装箱操作
    Javascript继承(原始写法,非es6 class)
    动态作用域与词法作用域
    自行车的保养
    探索JS引擎工作原理 (转)
    C语言提高 (7) 第七天 回调函数 预处理函数DEBUG 动态链接库
    C语言提高 (6) 第六天 文件(续) 链表的操作
    C语言提高 (5) 第五天 结构体,结构体对齐 文件
    C语言提高 (4) 第四天 数组与数组作为参数时的数组指针
    C语言提高 (3) 第三天 二级指针的三种模型 栈上指针数组、栈上二维数组、堆上开辟空间
  • 原文地址:https://www.cnblogs.com/xiaoxian1369/p/2127447.html
Copyright © 2011-2022 走看看