模素数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)
/* * hdu3930.c * * Created on: 2011-10-12 * Author: bjfuwangzhu */ #include<math.h> #include<stdio.h> #include<string.h> #include<stdlib.h> #define LL long long #define nmax 1000010 typedef struct num { int ii; LL value; } num; num Num[nmax]; int flag[nmax], prime[nmax], cpfactor[100]; LL pfactor[100]; int plen, len_pfactor; LL k, n, p, proot, x, y; void mkprime() { int i, j; memset(flag, -1, sizeof(flag)); for (i = 2, plen = 0; i < nmax; i++) { if (flag[i]) { prime[plen++] = i; } for (j = 0; (j < plen) && (i * prime[j] < nmax); j++) { flag[i * prime[j]] = 0; if (i % prime[j] == 0) { break; } } } } void findpFactor(LL n) { int i, te, cnt; te = (int) sqrt(n * 1.0); 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] = (LL) prime[i]; cpfactor[len_pfactor++] = cnt; } } if (n > 1) { pfactor[len_pfactor] = n; cpfactor[len_pfactor++] = 1; } } LL modular_multi(LL a, LL b, LL c) { LL res, temp; res = 0, temp = a % c; while (b) { if (b & 1) { res += temp; if (res >= c) { res -= c; } } temp <<= 1; if (temp >= c) { temp -= c; } b >>= 1; } return res; } /*快速幂取余a^b%c*/LL modular_exp(LL a, LL b, LL c) { LL res, temp; res = 1 % c, temp = a % c; while (b) { if (b & 1) { res = modular_multi(res, temp, c); } temp = modular_multi(temp, temp, c); b >>= 1; } return 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; } } } LL extend_gcd(LL a, LL b) { LL 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(LL 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; LL temp = n.value - m.value; if (temp > 0) { return 1; } else if (temp < 0) { return -1; } return 0; } /* a^x = b (mod c)*/LL baby_step_giant_step(LL a, LL b, LL c) { int i, j, te; LL temp, xx, aa; te = (int) (sqrt(c * 1.0) + 0.5); for (i = 0, temp = 1 % c; i <= te; i++) { Num[i].ii = i; Num[i].value = 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 = x; xx = xx * b; xx = xx % c + c; x = xx % c; j = bfindNum(x, te + 1); if (j != -1) { return (LL) (i) * te + j; } temp = temp * aa % c; } return -1; } int rcmp(const void *a, const void *b) { LL temp = *(LL *) a - *(LL *) b; if (temp > 0) { return 1; } else if (temp < 0) { return -1; } return 0; } /* ax = b (mod c)*/LL result[1001]; void solve(LL a, LL b, LL c) { int i; LL d; d = extend_gcd(a, c); if (b % d) { puts("-1"); return; } b /= d, c /= d; result[0] = ((LL) x * b % c + c) % c; for (i = 1; i < d; i++) { result[i] = result[i - 1] + c; } 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("%I64d\n", result[i]); } } int main() { #ifndef ONLINE_JUDGE freopen("data.in", "r", stdin); #endif int cas; LL a, b, c; mkprime(); cas = 0; /*x^k = n (mod p) */ while (~scanf("%I64d %I64d %I64d", &k, &p, &n)) { primitive(); b = baby_step_giant_step(proot, n, p); a = k, c = p - 1; printf("case%d:\n", ++cas); solve(a, b, c); } return 0; }