HDU 2815 Mod Tree 解a^x = b(mod n)非互质

来源:互联网 发布:开淘宝网店怎么上货 编辑:程序博客网 时间:2024/04/30 18:55

题意:

求模方程 a^x = b(mod n)是否存在解x,如果存在,输出最小的x。

解题思路:

首先考虑简单的情况,求a^x = b(mod n),如果a,n互质,由欧拉定理 a^( phi(n) ) = 1 (mod n)可知,当x>phi(n)后a^x就开始循环了。所以只需要检查前phi(n)项是否有解,因为phi(n) <= n,为了方便,统一设定检查范围为0到n。然后我们先检查前m项 (令m = sqrt(n) ),保存所有a^i mod n的值 (0 <= i < m),接下来对于a^(m),a^(m+1)...a^(2m+1)就不用枚举来检查了,如果他们当中有解,则相当于存在a^i* a^m = b(mod n)。两边左乘a^(-m)得 a^i = ( b*a^(-m) ) (mod n),所以只需要判断有没有a^i = b*a^(-m) 。

如果a,n不互质的话,直接这样子做就不行了,既然我们有了a,n互质的做法,那就要想办法使得a,n互质。

所以每次都要把a,n的gcd约去,同时b也要约去gcd,如果b不能约去gcd说明无解。这样假设需要cnt个a和n约去才能使得a,n互质,这cnt个a约后得到的设为now,结果就是求now*a^x = b (mod n),也就转化成a,n互质的情况了,这样就很简单了~贴个代码 (ps:貌似好久没写博客了)


#include <stdio.h>#include <math.h>#include <map>using namespace std;#define LL __int64int exgcd(int a, int b, int &x, int &y) {    if(!b) {        x = 1; y = 0;        return a;    }    int ret = exgcd(b, a%b, y, x);    y -= a/b*x;    return ret;}int gcd(int a, int b) {    return b ? gcd(b, a%b) : a;}// 求逆元int inv(int a, int n) {    int x, y;    int d = exgcd(a, n, x, y);    if(x < 0)   x += n;    return x;}int mul_mod(LL a, LL b, int n) {    return a * b % n;}int pow_mod(int x, int n, int m) {    int ret = 1;    while(n) {        if(n&1) ret = (LL)ret*x%m;        x = (LL)x*x%m;        n /= 2;    }    return ret;}//求解a^x = b (mod n) a, n互质int log_mod(int a, int b, int n) {    int m = sqrt(n+0.5);    int v = inv(pow_mod(a, m, n), n);    map<int,int> x;    x[1] = 0;    int e = 1;    for(int i = 1;i < m; i++) {        e = mul_mod(e, a, n);        if(!x.count(e)) x[e] = i;    }    for(int i = 0;i < m; i++) {        if(x.count(b))  return i*m + x[b];        b = mul_mod(b, v, n);    }    return -1;}int solve(int a, int p, int b) {    int cnt = 0;    int now = 1;    while(true) {        // 结果已经等于b的情况        if(now%p == b)  return cnt;        int d = gcd(a, p);        if(d == 1) {            int v = inv(now, p);            int ret = log_mod(a, (LL)b*v%p, p);            if(ret == -1)   return -1;            return ret + cnt;        }        if(b % d)   return -1;        b /= d;        p /= d;        now = (LL)now*(a/d)%p;        cnt++;    }}int main() {    int a, p, b;    while(scanf("%d%d%d", &a, &p, &b) != -1) {        if(b >= p) {            puts("Orz,I can’t find D!"); continue;        }        int ans = solve(a, p, b);        if(ans == -1)   puts("Orz,I can’t find D!");        else    printf("%d\n", ans);     }    return 0;}


原创粉丝点击