题意

给定正整数 L 满足 L\in[2, 10^9],问至少多少个 8 连起来组成的正整数是 L 的倍数

思路

首先设 x8 连起来,这个数记为 \displaystyle \frac{8(10^x-1)}{9},题意就是求最小正整数 x 使得 L\mid \displaystyle \frac{8(10^x-1)}{9}

首先将式子化为 9L\mid 8(10^x – 1),两边同时约去 d=\gcd(L, 8) 得到 \displaystyle \frac{9L}{d} \mid 10^x – 1

所以原式化为

10^x\equiv 1\pmod{\frac{9L}{d}}

引理

若正整数 a\perp n,则满足 a^x\equiv 1\pmod n 的最小正整数 x_0\varphi(n) 的约数。

使用欧拉定理 a^{\varphi(n)}\equiv 1\pmod n 可以证明

所以设 p = \varphi\left(\displaystyle \frac{9L}{d}\right),枚举其所有约数 x,符合条件即为答案。

模数可能为 long long,要开快速乘

#include <cstdio>
#include <cmath>
#include <queue>
#include <algorithm>
#define int long long

int gcd(int a, int b)
{
    if (!b) return a;
    return gcd(b, a % b);
}

int phi(int n)
{
    int ans = n, sq = sqrt(n);
    for (int i = 2; i <= sq; ++i)
    {
        if (n % i == 0)
        {
            ans = ans / i * (i - 1);
            while (n % i == 0)
                n /= i;
        }
    }
    if (n > 1)
        ans = ans / n * (n - 1);
    return ans;
}

int mul(int a, int b, int mod)
{
    int ans = 0, x = a;
    b = (b + mod) % mod, a = (a + mod) % mod;
    for (; b; b >>= 1ll)
    {
        if (b & 1ll)
            ans = (ans + x) % mod;
        x = (x << 1) % mod;
    }
    return ans;
}

int ksm(int base, int p, int mod)
{
    int ans = 1;
    base %= mod;
    for (; p; p >>= 1)
    {
        if (p & 1)
            ans = mul(ans, base, mod);
        base = mul(base, base, mod);
    }
    return ans;
}

std::vector<int> fact;

signed main()
{
    int n;
    for (signed kase = 1; ; ++kase)
    {
        scanf("%lld", &n);
        if (!n)
            return 0;
        int d = gcd(n, 8);
        int phip = phi(9 * n / d), sqrtp = sqrt(phip);
        fact.clear();
        for (int i = 2; i <= sqrtp; ++i)
            if (phip % i == 0)
            {
                fact.push_back(i);
                if (phip / i != i)
                    fact.push_back(phip / i);
            }
        std::sort(fact.begin(), fact.end());
        int ans = 0;
        for (int i = 0; i < fact.size(); ++i)
        {
            if (ksm(10, fact[i], 9 * n / d) == 1)
            {
                ans = fact[i];
                break;
            }
        }
        printf("Case %d: %lld\n", kase, ans);
    }
    return 0;
}
最后修改日期:2021年1月6日

作者

留言

撰写回覆或留言

发布留言必须填写的电子邮件地址不会公开。