http://www.cnblogs.com/wondove/p/8590582.html
这篇博客讲得挺好哒
当a与n互质时,a对于mod n才有逆元
1.欧拉公式 a ^ phi(p) = 1 (mod p) 要求a与p互质
2.扩展gcd
均可以解决逆元的问题
高次同余方程 A^x = B (mod p) 求x
1.A与p互质
m = [sqrt(p)] (分块)
令x = i * m + j
A ^ x = A ^ (i * m + j) = B (mod p)
A ^ j = B * A ^ ( -m * i ) (mod p) // j范围在(0,m),先预处理A ^ j , O( sqrt(p) )
再枚举i ,对于每个i,在A ^ j中找有没有和右边式子B * A ^ (- m * i) (mod p)相等的
(用二分的话 O (sqrt(p) * log p) 哈希大概就是O (sqrt (p) ) )
2.A与p不互质
d = gcd(A , p)
A ^ x = B (mod p) -> A ^ x - p * y = B
两边同除p
A' * A ^ (x - 1) - p' * y = B'
A' * A ^ (x - 1) = B' (mod p') 这样不断循环,将左边每次A‘乘起来,标记为D,直到A与p互质为止
并且如果B不整除d说明无解
num记录一共除d次数
D * A ^ (x - num) = B (mod p) A和p互质,可按传统方法计算
poj2417 (题目给的p是质数,所以不需要考虑A和p不互质的情况)
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn =5e4;
typedef long long ll;
ll Aj[maxn];
struct node{
ll aj,j;
bool operator < (constnode & a)const{
return aj < a.aj || (aj == a.aj &&j< a.j);
}
}ns[maxn],t;
ll qk_pow(ll a,ll b,ll p)
{
ll ans = 1,k = a;
while (b) {
if(b & 1) ans = (ll)ans * k % p;
k = (ll)k * k % p;
b >>= 1;
}
return ans;
}
int main()
{
ll p,A,B;
while (scanf("%lld%lld%lld",&p,&A,&B) !=EOF) {
ll m = sqrt(0.5 + p);
Aj[0] =1;ns[0] =node{1,0};
for (ll i =1; i <= m; i ++) {
Aj[i] = Aj[i -1] * A % p;
ns[i] = node{Aj[i],i};
}
sort(ns,ns + m +1);
ll ans = -1;
for (ll i =0; i <= m +2; i ++) {
ll ex = (-m * i % (p - 1) + p - 1) % (p - 1);
ll k = B * qk_pow(A,ex,p) % p;
t = node{k,0};
ll pos = lower_bound(ns, ns + 1 + m, t) - ns;
if(pos != m + 1 && ns[pos].aj == k){
ans = i * m + ns[pos].j;
break;
}
}
if(ans == -1)printf("no solution\n");
else printf("%lld\n",ans);
}
return 0;
}
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll ;
const int maxn = 5e4 + 5;
ll gcd(ll a,ll b){
if(!b) return a;
return gcd(b,a % b);
}
void exgcd(ll a,ll b,ll &x,ll &y,ll &d){
if(!b){
x = 1,y = 0;
d = a;
return ;
}
exgcd(b, a % b, y, x, d);
y -= a / b * x;
}
ll inval(ll b,ll p){
ll x,y,d;
exgcd(b, p, x, y, d);
return x < 0 ? x + p : x;//!!!
}
struct node{
ll aj,j;
bool operator < (const node &a) const{
return aj < a.aj || (aj == a.aj && j < a.j);
}
}ns[maxn];
ll qk_pow(ll a,ll b,ll p)
{
ll ans = 1ll,k = a;
while(b){
if(b & 1) ans = ans * k % p;
k = k * k % p;
b >>= 1;
}
return ans;
}
int BSGS(ll A,ll B,ll p)
{
ll tmp;
for(int i = 0,tmp = 1 % p;i < 100;i ++,tmp = tmp * A % p){//p == 1
if(tmp == B) return i;
}
//1.小范围暴力 2.tmp = 1 % p是为了p = 1的情况
int num = 0;
ll d,D = 1 % p;
while((d = gcd(A,p)) != 1ll){
if(B % d) return -1;
B /= d;p /= d;num ++;
D = A / d * D % p;
}
int m = sqrt(p);
tmp = 1 % p;
for (int i = 0; i <= m; i ++,tmp = tmp * A % p) {
ns[i] = node{tmp,i};
}
sort(ns,ns + 1 + m);
int am = qk_pow(A, m, p);
for (int i = 0; i <= m; i ++,D = D * am % p) {
int tmp = inval(D, p) * B % p;
int pos = lower_bound(ns, ns + 1 + m, node{tmp,0}) - ns;
if(pos != m + 1 && ns[pos].aj == tmp) return i * m + ns[pos].j + num;
}
return -1;
}
int main()
{
ll A,B,p;
while (scanf("%lld%lld%lld",&A,&p,&B) != EOF) {
if(B >= p){
puts("Orz,I can’t find D!");
continue;
}
int ans = BSGS(A,B,p);
if(ans == -1) puts("Orz,I can’t find D!");
else printf("%d\n",ans);
}
return 0;
}
poj3243 A与p不互质
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn =5e4;
typedef long long ll;
ll Aj[maxn];//需要快速找到Aj[i]是否等于某个数,所以需要Hash,Hash的话总体复杂度为O(sqrt(p))
struct node{
ll aj;
int j;
bool operator < (constnode &a)const{
return aj < a.aj || (aj == a.aj &&j < a.j);
}
}ns[maxn],t;//二分复杂度仍为O(sqrt(p) * log2p)
ll qk_pow(ll a,ll b,ll p)
{
ll k = a,res = 1;
while (b) {
if(b & 1) res = (ll)res * k % p;
k = (ll)k * k % p;
b >>= 1;
}
return (res % p + p) % p;
}
ll gcd(ll a,ll b){
if(b == 0)return a;
return gcd(b , a % b);
}
int getphi(int p)
{
int ans = p;
for (int i =2; i <=sqrt(0.5 + p); i ++) {
if(p % i == 0){
ans = ans / i * (i - 1);
while (p % i == 0) p /= i;
}
if(p == 1)break;
}
if(p > 1) ans = ans / p * (p -1);
return ans;
}
int main()
{
ll A,B,p;
while (scanf("%lld%lld%lld",&A,&p,&B) !=EOF) {
if(A == 0 && B ==0 && p ==0)break;
B %= p;
ll D = 1,d =1;
int num = 0;
bool fg = 1;
while ((d = gcd(A,p)) != 1ll) {
if(B % d){fg = 0;break;}
B /= d;
p /= d;
num ++;
D = D * A / d % p;
}
if(!fg) {printf("No Solution\n");continue;}
int m = sqrt(p);
Aj[0] =1;ns[0] =node{1,0};
for (int i =1; i <= m; i ++) {
Aj[i] = Aj[i - 1] * A % p;
ns[i] = node{Aj[i],i};
}
sort(ns,ns +1 + m);
t.aj =0;t.j =0;
int fp = getphi(p);
B = B * qk_pow(D,fp - 1,p) % p;
int x = -1;
for (int i =0; i <= m +2; i ++) {
ll k = (-m * i % fp + fp) % fp;
t.aj = B *qk_pow(A, k, p) % p;
int pos = lower_bound(ns,ns + m +1,t) -ns;
if(pos != m + 1 && ns[pos].aj ==t.aj){
x = ns[pos].j + i * m + num;
break;
}
}
if(x == -1)printf("No Solution\n");
else printf("%d\n",x);
}
return 0;
}