2219: 数论之神

有了OneNote很少往博客上发东西了 今天还是纪念下 AC了数论之神 看了一周数论ORZ

 

代码虽然长但是封装的很好 我这样智商捉急的只能这样写代码了 神犇都是像seter一样写代码 像mato一样发题解

 

mato这题的题解简直了 一句话我要推半天 唉

 

#include <map>
#include <cmath>
using namespace std;
typedef long long LL;
const int N = 101000;
LL pw(LL a, int k) {
    LL z(1);
    for (; k; k >>= 1) {
        if (k & 1) z = z * a;
        a = a * a;
    }
    return z;
}
int gcd(int a, int b) {
    return b ? gcd(b, a % b) : a;
}
LL pw(LL x, int k, LL p) {
    LL z = 1;
    for (; k; k >>= 1) {
        if (k & 1) z = z * x % p;
        x = x * x % p;
    }
    return z;
}
bool vis[N];
int pr[N];
void getpr() {
    int N = 100000;
    memset (vis, 0, sizeof vis);
    int cnt = 0;
    for (int i = 2; i <= N; i ++) {
        if (!vis[i])
            pr[++ cnt] = i;
        for (int j = 1; j <= cnt; j ++) {
            if (i * pr[j] > N) break;
            vis[i * pr[j]] = true;
            if (i % pr[j] == 0) break;
        }
    }
}
struct ROOT {
    int n, a_c;
    int a[N];
    void divide(int n) {
        for (int i = 1; pr[i] * pr[i] <= n; i ++) {
            if (n % pr[i] != 0) continue;
            a[++ a_c] = pr[i];
            while(n % pr[i] == 0) n /= pr[i];
        }
        if (n != 1) a[++ a_c] = n;
    }
    bool ck(int x) {
        for (int i = 1; i <= a_c; i ++)
            if (pw(x, n / a[i], n) == 1)
                return false;
        return true;
    }
    int get(int _n) {
        a_c = 0;
        n = _n;
        divide(n - 1);
        int i;
        for (i = 2; ; i ++) {
            if (ck(i))
                return i;
        }
    }
}root;

const int HN = 40000, M = 100000, HEAD = 39997;
struct HASH {
    int cnt, head[HN], next[M], len[M], key[M];
    HASH() {
        clear();
    }
    inline void clear() {
        memset (head, -1, sizeof head);
        cnt = 0;
    }
    inline void ADD(int x, int y, int w) {
        key[cnt] = y;
        next[cnt] = head[x];
        len[cnt] = w;
        head[x] = cnt ++;
    }
    inline int GETHEAD(int idx) {
        return idx % HEAD;
    }
    inline void add(int idx, int val) {
        int h = GETHEAD(idx);
        ADD(h, idx, val);
    }
    bool find(int idx) {
        int h = GETHEAD(idx);
        for (int i = head[h]; ~ i; i = next[i])
            if (key[i] == idx)
                return true;
        return false;
    }
    int get(int idx) {
        int h = GETHEAD(idx);
        for (int i = head[h]; ~ i; i = next[i])
            if (key[i] == idx)
                return len[i];
    }
}_hash;
int BSGS(int a, int b, int p) {
    a %= p, b %= p;
    if (b == 1) return 0;
    int cnt = 0;
    LL t = 1;
    for (int g = gcd(a, p); g != 1; g = gcd(a, p)) {
        if (b % g) return -1;
        p /= g, b /= g, t = t * a / g % p;
        ++cnt;
        if (b == t) return cnt;
    }
    _hash.clear();
    int m = int(sqrt(1.0 * p) + 0.5);
    LL base = b;
    for (int i = 0; i < m; i ++) {
        _hash.add(base, i);
        base = base * a % p;
    }
    base = pw(a, m, p);
    LL now = t;
    for (int i = 1; i <= m + 1; ++i) {
        now = now * base % p;
        if (_hash.find(now))
            return i * m - _hash.get(now) + cnt;
    }
    return -1;
}
int a[N], c[N], a_c;
void Divide(int n) {
    a_c = 0;
    memset (c, 0, sizeof c);
    for (int i = 1; pr[i] * pr[i] <= n; i ++) {
        if (n % pr[i] != 0) continue;
        a[++ a_c] = pr[i];
        while(n % pr[i] == 0) n /= pr[i], c[a_c]++;
    }
    if (n != 1) {
        a[++ a_c] = n;
        c[a_c] = 1;
    }
}
int A, B, p;
int main() {
    freopen("a.in", "r", stdin);
    getpr();
    int T;
    scanf("%d", &T);
    while(T --) {
        scanf("%d%d%d", &A, &B, &p);
        a_c = 0;
        p = 2 * p + 1;
        Divide(p);
        bool flag = false;
        LL ans = 1;
        for (int i = 1; i <= a_c; i ++) {
            int t = pw(a[i], c[i]);
            int b = B % t;
            if (!b) {
                ans = ans * pw(a[i], c[i] - (c[i] - 1) / A - 1);
            }
            else {
                int g = gcd(b, t);
                b /= g, t /= g;
                int cnt = 0;
                while(g % a[i] == 0) g /= a[i], cnt ++;
                if (cnt % A) {
                    ans = 0;
                    break;
                }
                int rt = root.get(a[i]);
                int I = BSGS(rt, b, t);
                int phit = t - pw(a[i], c[i] - 1);
                int D = gcd(A, phit);
                if (I % D) {
                    ans = 0;
                    break;
                }
                if (cnt)
                    ans = ans * D * pw(a[i], cnt - cnt / A);
                else
                    ans = ans * D;
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

 

posted @ 2015-08-29 01:10  Moretimes  阅读(287)  评论(0编辑  收藏  举报