数论--高次同余方程 A^x = B (mod p) --Baby Step Giant Step 及扩展BSGS算法

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;

}

hdu2815 A与p不互质


#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;

}




猜你喜欢

转载自blog.csdn.net/sm_545/article/details/79595411
今日推荐