模素数p的原根g的优美体现在每个模p的非零数以g的幂次出现。所以,对任何数1 <= a < p,我们可选择幂
g,g^2,g^2,```````,g^(p-2),g^(p-1)
中恰好一个与a模p同余。相应的指数被称为以g为底的a模p的指标。假设p与g已给定,则记指标为I(a)。
以下以2模13的所有幂的形式:
I 1 2 3 4 5 6 7 8 9 10 11 12
2^I(mod 13) 2 4 8 3 6 12 11 9 5 10 7 1
例如,为求I(11),我们搜寻表的第二行直到找到数11,则指标I(11)=7可从第一行得到。
指标法则
a). I(ab)=I(a)+I(b) (mod p-1)
b). I(a^k)=kI(a) (mod p-1)
g^I(ab)=ab=g^I(a)g^I(b)=g^(I(a)+I(b)) (mod p)
故有g^I(x) = x (mod p-1)
也可以这么理解:g^I(value) = id (mod p-1)
例题:3*x^30=4(mod 37)
I(3*x^30)=I(4)
I(3)+30*I(x)=I(4) (mod 36)
26+30*I(x)=2 (mod 36)
30*I(x)=-24=12 (mod 36)
对于这里I(4)=2解释一下:
其实就是g^2 = 4 (mod 36)
其实这个可以根据g^x =b (mod p)来求
对于本题,g就是37的原根2,b=I(x) p =36
也就是求满足2^x = I(x) (mod 36)的x。用Baby Step Giant Step算法即可哦
提醒:两边不要除以6以得到5*I(x)+2 (mod 36),否则会丢失一些解。
ax = c (mod m)
由扩展欧几里德,知:
I(x)=4,10,16,22,28,34
最后,有指标表(书论书上有哦,自己不放写程序看看),得到x的对应值
I(16)=4,I(25)=10,I(9)=16
I(21)=22,I(12)=28,I(28)=34
其实这里,也可以根据指标的原式公式g^I(x) = x (mod p-1)
故,同余式3*x^30=4 (mod 37)有6个解,即
x=16,25,9,21,12,28 (mod 37)
/* * hrbeu1318.c * * Created on: 2011-10-13 * Author: bjfuwangzhu */ #include<stdio.h> #include<math.h> #include<string.h> #include<stdlib.h> #define LL long long #define nmax 4001 typedef struct num { int ii, value; } num; num Num[nmax]; int flag[nmax], prime[nmax], pfactor[nmax], cpfactor[nmax]; int plen, len_pfactor, k, n, p, proot, x, y; void mkprime() { int i, j; memset(prime, -1, sizeof(prime)); for (i = 2; i < nmax; i++) { if (prime[i]) { for (j = i + i; j < nmax; j += i) { prime[j] = 0; } } } for (i = 2, plen = 0; i < nmax; i++) { if (prime[i]) { prime[plen++] = i; } } } void findpFactor(int n) { int i, te, cnt; te = (int) sqrt(1.0 * n); for (i = 0, len_pfactor = 0; (i < plen) && (prime[i] <= te); i++) { if (n % prime[i] == 0) { cnt = 0; while (n % prime[i] == 0) { cnt++; n /= prime[i]; } pfactor[len_pfactor] = prime[i]; cpfactor[len_pfactor++] = cnt; } } if (n > 1) { pfactor[len_pfactor] = n; cpfactor[len_pfactor++] = 1; } } /*快速幂取余a^b%c*/ int modular_exp(int a, int b, int c) { LL res, temp; res = 1 % c, temp = a % c; while (b) { if (b & 1) { res = res * temp % c; } temp = temp * temp % c; b >>= 1; } return (int) res; } int dfs(int depth, LL now) { int i; LL res, temp; if (depth == len_pfactor) { res = modular_exp(proot, now, p); if ((res == 1) && (now != (p - 1))) { return 0; } return 1; } for (i = 0, temp = 1; i <= cpfactor[depth]; i++) { if (!dfs(depth + 1, now * temp)) { return 0; } temp = temp * pfactor[depth]; } return 1; } void primitive() { findpFactor(p - 1); for (proot = 2;; proot++) { if (dfs(0, 1)) { return; } } } int extend_gcd(int a, int b) { int d, xx; if (b == 0) { x = 1, y = 0; return a; } d = extend_gcd(b, a % b); xx = x; x = y, y = xx - a / b * y; return d; } 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; } int cmp(const void *a, const void *b) { num n = *(num *) a; num m = *(num *) b; return n.value - m.value; } /* a^x = b (mod c)*/ int baby_step_giant_step(int a, int b, int c) { int i, j, te, aa; LL temp, xx; te = (int) (sqrt(1.0 * c) + 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) { return i * te + j; } temp = temp * aa % c; } return -1; } int rcmp(const void *a, const void *b) { return *(int *) a - *(int *) b; } /* ax = b (mod c)*/ int result[nmax]; void solve(int a, int b, int c) { int i, d, cc; d = extend_gcd(a, c); if (b % d) { puts("No Solution!"); return; } cc = c; b /= d, c /= d; result[0] = ((LL) x * b % c + c) % c; for (i = 1; i < d; i++) { result[i] = (result[i - 1] + c) % cc; } for (i = 0; i < d; i++) { result[i] = modular_exp(proot, result[i], p); } qsort(result, d, sizeof(result[0]), rcmp); for (i = 0; i < d; i++) { printf("%d\n", result[i]); } } int main() { #ifndef ONLINE_JUDGE freopen("data.in", "r", stdin); #endif int a, b, c; mkprime(); /*x^k = n (mod p) */ while (~scanf("%d %d %d", &k, &p, &n)) { primitive(); b = baby_step_giant_step(proot, n, p); a = k, c = p - 1; solve(a, b, c); printf("\n"); } return 0; }