突然发现 WC2021 到现在还没做 ..

考虑我们要求的应该是最小的 $i$ 使得满足 $f_{i-1}a\equiv f_{i}b\pmod {p}$ 。

即满足 $p|f_{i-1}a-f_ib$,因此 $\frac{p}{\gcd(p,a,b)}|f_{i-1}\frac{a}{\gcd(p,a,b))}-f_i\frac{b}{\gcd (p,a,b)}$,记 $g=\gcd(p,a,b)$ 即有 $\frac{p}{g}|f_{i-1}\frac{a}{p}-f_i\frac{b}{g}$ 。

此时观察 $f_{i-1}\frac{a}{g}\equiv f_i\frac{b}{g}\pmod{\frac{p}{g}}$,显然有 $f_i\perp f_{i-1}$ 。记 $g’=\gcd(\frac{a}{p},\frac{b}{p})$ 存在 $g’\perp \frac{p}{g}$ ,此时令 $a’=\frac{a}{gg’},b’=\frac{b}{gg’},p’=\frac{p}{g}$ 。要解决的新问题变为 $f_{i-1}a’\equiv f_{i}b’\pmod {p’}$,同时有 $a’\perp b’$ 。

此时考虑令 $g_a=\gcd (a’,p’)$,即 $f_{i-1}\frac{a’}{g_a}g_a-f_{i}b=k_pp’\frac{p’}{g_a}g_a$,因此 $\left(f_{i-1}\frac{a’}{g_a}-k_pp’\frac{p’}{g_a}\right)g_a=f_{i}b$,这说明 $g_a|f_ib$,即 $g_a|f_i$ 。

同理令 $g_b=\gcd(b’,p’)$,可证 $g_{b}|f_{i-1}$ 。因此我们需要解决 $\frac{f_{i-1}}{g_{b}}\frac{a’}{g_a}\equiv \frac{f_i}{g_a}\frac{b’}{g_b}\pmod{\frac{p’}{g_ag_b}}$,此时显然有 $\frac{b’}{g_b}\perp\frac{p’}{g_ag_b}$。对于证明 $\frac{f_{i-1}}{g_b}\perp \frac{p’}{g_ag_b}$ 考虑反证,若存在 $\gcd(\frac{f_{i-1}}{g_b},\frac{p’}{g_ag_b})=d$ 且 $d>1$,即有 $d|\frac{f_i}{g_a}\frac{b’}{g_b}$,也即 $d|\frac{b’}{g_b}$,这与 $\frac{b’}{g_b}\perp\frac{p’}{g_ag_b}$ 相矛盾。

因此上述两者都存在模 $\frac{p’}{g_ag_b}$逆元,我们需要处理的问题变成了 $\frac{a’}{g_a}\left(\frac{b’}{g_b}\right)^{-1}\equiv \frac{f_i}{g_a}\left(\frac{f_{i-1}}{g_b}\right)^{-1}\pmod{\frac{p’}{g_ag_b}}$ 。此时可以发现,因为存在 $g_a\perp f_{i-1}$,因此 $\gcd(f_{i-1},p’)=g_b$ 和 $g_a$ 无关,同理可得 $\gcd(f_{i},p)=g_a$ 。即 $\gcd(f_{i-1},p’)=\gcd(b’,p’)$,同理可得 $\gcd(f_{i},p’)=\gcd (a’,p’)$ 。

考虑到 $p’ |m$,而模 $m$ 意义下斐波那契序列的循环节长度为 $O(m)$,$m$ 的因子和数量级为 $O(m\log\log m)$,考虑用 hash 表预处理所有可能的 $(\gcd(f_i,p’),\gcd(f_{i-1},p’),\frac{f_i}{g_a}\left(\frac{f_{i-1}}{g_b}\right)^{-1}\bmod \frac{p’}{g_ag_b})$ 即可。

 #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define debug(...) fprintf (stderr, __VA_ARGS__)

#define lep(i, l, r) for (int i = (l), i##_end = (r); i <= i##_end; ++ i)
#define rep(i, r, l) for (int i = (r), i##_end = (l); i >= i##_end; -- i)

char __c; bool __f; template <class T> inline void IN (T & x) {
    __f = 0, x = 0; while (__c = getchar (), ! isdigit (__c)) if (__c == '-') __f = 1;
    while (isdigit (__c)) x = x * 10 + __c - '0', __c = getchar (); if (__f) x = -x;
}

template <class T> inline void chkmin (T & x, T y) { if (x > y) x = y; }
template <class T> inline void chkmax (T & x, T y) { if (x < y) x = y; }

struct barrett {
    int p; __int128 w;
    inline void init (int mod) { p = mod, w = - 1ull / p; }
    inline int reduce (ll x) {
        ll t = x - (w * x >> 64) * p;
        return t >= p ? t - p : t;  
    }
} __mod;

inline int mul (int x, int y) { return __mod.reduce (1ll * x * y); }

int gcd (int x, int y) { return y ? gcd (y, x % y) : x; }
void exgcd (int x, int y, int &a, int &b) {
    if (! y) return a = 1, b = 0, void ();
    return exgcd (y, x % y, b, a), b -= (x / y) * a, void ();
}
inline int inv (int x) {
    int a, b; exgcd (x, __mod.p, a, b);
    return __mod.reduce (__mod.reduce (a) + __mod.p);
}

const int N = 1e5 + 5;
const ll B2 = 1e12, B1 = 1e6;

int m, a, b;
unordered_map <ll, int> mp[N];

inline ll zip (int ga, int gb, int _inv) { return B2 * ga + B1 * gb + _inv; }

inline void init (const int L = N - 5) {
    lep (p, 2, m) if ((m % p) == 0) {
        int f0 = 1, f1 = 1;

        for (int i = 2; ; ++ i) {
            int ga = gcd (f1, p);
            int gb = gcd (f0, p);

            __mod.init (p / ga / gb);
            ll key = zip (ga, gb, mul (f1 / ga, inv (f0 / gb)));
            if (! mp[p].count (key)) mp[p][key] = i;

            int f2 = (f0 + f1) % p;
            if (f0 = f1, f1 = f2, f0 == 1 && f1 == 1) break ;
        }
    }
}
signed main () {
    int T;
    IN (T), IN (m), init ();

    while (T -- ) {
        int p = m; __mod.init (p);

        IN (a), a = __mod.reduce (a); 
        IN (b), b = __mod.reduce (p - __mod.reduce (b));
        if (a == 0) { puts ("0"); continue ; }
        if (b == 0) { puts ("1"); continue ; }

        int g1 = gcd (a, b), g0 = gcd (g1, p);
        a = a / g1, b = b / g1, p = p / g0;

        int ga = gcd (a, p);
        int gb = gcd (b, p);

        __mod.init (p / ga / gb);
        ll key = zip (ga, gb, mul (a / ga, inv (b / gb)));

        if (mp[p].count (key)) printf ("%d\n", mp[p][key]);
        else puts ("-1");
    }
    return 0;
}
分类: 文章

Qiuly

QAQ

0 条评论

发表回复

Avatar placeholder

您的电子邮箱地址不会被公开。 必填项已用 * 标注