1 条题解

  • 0
    @ 2026-10-26 15:31:29

    思路与算法

    以斐波那契转移矩阵Q观察Q^60≡I(mod10)。若Q^P≡I(mod10^k),则(Q^P)^10≡I(mod10^(k+1)),所以60×10^(k-1)始终是合法周期,无需它最小。先枚举0..59中F与a模10一致的下标,逐层将每个候选扩成x+jP,j=0..9,用快速倍增模当前10次幂计算并筛选,直到10^13。无候选输出-1,否则最小候选即首次出现。

    正确性说明

    合法周期保证任何更大层周期内的下标唯一写作旧余数x加jP。能在高层匹配的下标在低层也匹配,因此不会被提前删掉;完整枚举全部十个提升保证无遗漏。快速倍增由F(2n)=F(n)(2F(n+1)-F(n))与F(2n+1)=F(n)^2+F(n+1)^2精确求值。最终所有下标按周期重复,最小代表就是第一次出现。

    复杂度

    初始60次计算;设各层候选数为Ck,总时间O(60log60+Σ10Ck logPk),Pk=60×10^(k-1),空间O(max Ck+logP13)。逐层向量初始化和全部候选均计入,不把候选数量假设为常数。

    易错点

    a=0首次下标0;a=1首次1而非2。模10^13的平方可达10^26,快速倍增使用128位中间乘积;周期6×10^13仍在64位范围。

    参考代码(C++11)

    #include <bits/stdc++.h>
    using namespace std;
    using ull = unsigned long long;
    pair<ull, ull> fib(ull n, ull m) {
        if (!n)
            return {0, 1};
        auto q = fib(n / 2, m);
        ull a = q.first, b = q.second;
        ull c = (__uint128_t)a * ((2 * b % m + m - a) % m) % m,
            d = ((__uint128_t)a * a + (__uint128_t)b * b) % m;
        return n % 2 ? make_pair(d, (c + d) % m) : make_pair(c, d);
    }
    int main() {
        ull a;
        cin >> a;
        vector<ull> v;
        for (ull i = 0; i < 60; i++)
            if (fib(i, 10).first == a % 10)
                v.push_back(i);
        ull period = 60, mod = 10;
        for (int k = 2; k <= 13; k++) {
            mod *= 10;
            vector<ull> w;
            for (ull x : v)
                for (ull j = 0; j < 10; j++) {
                    ull y = x + j * period;
                    if (fib(y, mod).first == a % mod)
                        w.push_back(y);
                }
            v.swap(w);
            period *= 10;
        }
        if (v.empty())
            cout << -1 << '\n';
        else
            cout << *min_element(v.begin(), v.end()) << '\n';
    }
    
    • 1

    信息

    ID
    1804
    时间
    1000ms
    内存
    512MiB
    难度
    提高
    标签
    递交数
    1
    已通过
    1
    上传者