题目-最幸运的数字

在这里插入图片描述

问题分析

题目的要求是 L    ∣ 88...8 L \; | 88...8 L88...8 8 8 8的最少位数
因为数字不好操作, 将 88...8 88...8 88...8转换为
8 ⋅ 11...1 8 \cdot 11...1 811...1
继续转化
8 ⋅ 99...9 9 = 8 ⋅ 1 0 x − 1 9 8 \cdot \frac{99...9}{9} = 8 \cdot \frac{10 ^ x - 1}{9} 8999...9=8910x1
也就是
L    ∣    8 ⋅ 1 0 x − 1 9 L \; | \; 8 \cdot \frac{10 ^ x - 1}{9} L8910x1
求最小的 x x x

假设 gcd ⁡ ( 8 , L ) = d \gcd(8, L) = d gcd(8,L)=d
9 L d    ∣    1 0 x − 1 \frac{9L}{d} \; | \; 10 ^ x - 1 d9L10x1

t = 9 L d t = \frac{9L}{d} t=d9L, 得到同余式

1 0 x ≡ 1 ( m o d    t ) 10 ^ x \equiv 1 (\mod t) 10x1(modt)

可以发现 1 0 x 10 ^ x 10x t t t必须互质, 也就是 10 10 10 t t t必须互质, 也就是说 gcd ⁡ ( 10 , t ) ≠ 1 \gcd(10, t) \ne 1 gcd(10,t)=1无解

既然 10 10 10 x x x互质, 那么有欧拉函数 a ϕ ( n ) ≡ 1 ( m o d    n ) a ^ {\phi(n)} \equiv 1(\mod n) aϕ(n)1(modn), 但是题目要求的是最小位数, 欧拉函数无法保证最小

猜想: 设 x x x是最小位数, 那么有 x    ∣    ϕ ( t ) x \; | \; \phi(t) xϕ(t), 也就是说 x x x ϕ ( t ) \phi(t) ϕ(t)的约数

证明: 假设 x x x不是 ϕ ( t ) \phi(t) ϕ(t)的约数, 我们设 ϕ ( t ) = q x + r    ( 0 < r < x ) \phi(t) = qx + r \; (0 < r < x) ϕ(t)=qx+r(0<r<x)
因为有 1 0 x ≡ 1 ( m o d    t ) 10 ^ x \equiv 1 (\mod t) 10x1(modt)
那么有 1 0 q x ≡ 1 ( m o d    t ) 10 ^ {qx} \equiv 1(\mod t) 10qx1(modt)

因为 1 0 ϕ ( x ) ≡ 1 ( m o d    t ) = 1 0 q x ⋅ 1 0 r ≡ 1 ( m o d    t ) 10 ^ {\phi(x)} \equiv 1 (\mod t) = 10 ^ {qx} \cdot 10 ^ r \equiv 1(\mod t) 10ϕ(x)1(modt)=10qx10r1(modt)
也就是说 1 0 r ≡ 1 ( m o d    t ) 10 ^ r \equiv 1(\mod t) 10r1(modt), 因为 r < x r < x r<x, 但是我们假设 x x x是最小的位数, 矛盾
因此 ϕ ( t ) = q x \phi(t) = qx ϕ(t)=qx, 也就是说最小位数 x x x t t t的一个约数, 证毕

算法步骤

  • 计算出 t = 9 L d t = \frac{9L}{d} t=d9L
  • 计算 ϕ ( t ) \phi(t) ϕ(t)
  • 枚举 ϕ ( t ) \phi(t) ϕ(t)的所有约数
  • 快速幂算法检查 1 0 c ≡ 1 ( m o d    t ) 10 ^ c \equiv 1 (\mod t) 10c1(modt), c c c ϕ ( t ) \phi(t) ϕ(t)的约数

算法瓶颈在枚举约数, 算法时间复杂度 O ( L ) O(\sqrt L) O(L )

枚举约数可以使用质因数分解 + d f s dfs dfs, 算法时间复杂度是 O ( d ( n ) ) O(d(n)) O(d(n)), 其中 d ( n ) d(n) d(n)是约数个数, 也就是 ( c 1 + 1 ) ( c 2 + 1 ) . . . ( c k + 1 ) (c_1 + 1)(c_2 + 1) ... (c_k + 1) (c1+1)(c2+1)...(ck+1)

代码实现

分解质因数 + d f s dfs dfs枚举约数优化生成约数代码
在这里插入图片描述
相较于直接枚举能快 100 m s 100ms 100ms左右

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair<LL, LL> PII;
const int N = 50010;

int L;
int primes[N], cnt;
bool st[N];
vector<PII> f;
vector<LL> divs;

void init(int n) {
   
    for (int i = 2; i <= n; ++i) {
   
        if (!st[i]) primes[cnt++] = i;
        for (int j = 0; primes[j] <= n / i; ++j) {
   
            st[i * primes[j]] = true;
            if (i % primes[j] == 0) break;
        }
    }
}

LL get_phi(LL n) {
   
    LL ans = n;
    for (int i = 0; primes[i] <= n / primes[i]; ++i) {
   
        int p = primes[i];
        if (n % p == 0) {
   
            ans = ans / p * (p - 1);
            while (n % p == 0) n /= p;
        }
    }
    if (n > 1) ans = ans / n * (n - 1);
    return ans;
}

LL gcd(LL a, LL b) {
   
    return b ? gcd(b, a % b) : a;
}

void dfs(int u, LL curr) {
   
    if (u == f.size()) {
   
        divs.push_back(curr);
        return;
    }

    LL p = f[u].first;
    for (int i = 0; i <= f[u].second; ++i) {
   
        dfs(u + 1, curr);
        curr *= p;
    }
}

LL mul(LL a, LL b, LL mod) {
   
    a %= mod;
    LL ans = 0;
    while (b) {
   
        if (b & 1) ans = (ans + a) % mod;
        a = (a + a) % mod;
        b >>= 1;
    }
    return ans;
}

LL q_pow(LL a, LL b, LL mod) {
   
    a %= mod;
    LL ans = 1;
    while (b) {
   
        if (b & 1) ans = mul(ans, a, mod);
        a = mul(a, a, mod);
        b >>= 1;
    }
    return ans;
}

void solve(int idx) {
   
    f.clear();
    divs.clear();

    LL d = gcd(8, L);
    LL t = (LL) 9 * L / d;

    if (gcd(10, t) != 1) {
   
        printf("Case %d: %d\n", idx, 0);
        return;
    }

    LL val = get_phi(t);

    LL j = val;
    for (int i = 0; primes[i] <= j / primes[i]; ++i) {
   
        int p = primes[i];
        if (j % p == 0) {
   
            int s = 0;
            while (j % p == 0) s++, j /= p;
            f.push_back({
   p, s});
        }
    }
    if (j) f.push_back({
   j, 1});
    dfs(0, 1);

    LL ans = 1e18;
    for (LL div : divs) {
   
        if (q_pow(10, div, t) == 1) ans = min(ans, div);
    }

    printf("Case %d: %lld\n", idx, ans);
}

int main() {
   
    ios::sync_with_stdio(false);
    cin.tie(0);

    init(N - 1);
    int T = 1;
    while (cin >> L, L) solve(T++);

    return 0;
}

直接枚举约数代码

注意因为数据范围非常大, get_phi函数输入类型是 l o n g l o n g long long longlong, 并且快速幂过程中乘积会爆 l o n g l o n g long long longlong, 需要龟速乘辅助快速幂计算

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
const int N = 50010;

int L;
int primes[N], cnt;
bool st[N];

void init(int n) {
   
    for (int i = 2; i <= n; ++i) {
   
        if (!st[i]) primes[cnt++] = i;
        for (int j = 0; primes[j] <= n / i; ++j) {
   
            st[i * primes[j]] = true;
            if (i % primes[j] == 0) break;
        }
    }
}

LL get_phi(LL n) {
   
    LL ans = n;
    for (int i = 0; primes[i] <= n / primes[i]; ++i) {
   
        int p = primes[i];
        if (n % p == 0) {
   
            ans = ans / p * (p - 1);
            while (n % p == 0) n /= p;
        }
    }
    if (n > 1) ans = ans / n * (n - 1);
    return ans;
}

LL gcd(LL a, LL b) {
   
    return b ? gcd(b, a % b) : a;
}

LL mul(LL a, LL b, LL mod) {
   
    a %= mod;
    LL ans = 0;
    while (b) {
   
        if (b & 1) ans = (ans + a) % mod;
        a = (a + a) % mod;
        b >>= 1;
    }
    return ans;
}

LL q_pow(LL a, LL b, LL mod) {
   
    a %= mod;
    LL ans = 1;
    while (b) {
   
        if (b & 1) ans = mul(ans, a, mod);
        a = mul(a, a, mod);
        b >>= 1;
    }
    return ans;
}

void solve(int idx) {
   
    LL d = gcd(8, L);
    LL t = (LL) 9 * L / d;

    if (gcd(10, t) != 1) {
   
        printf("Case %d: %d\n", idx, 0);
        return;
    }

    LL val = get_phi(t);
    LL ans = 1e18;

    for (LL i = 1; i <= val / i; ++i) {
   
        if (val % i == 0) {
   
            LL d1 = i;
            LL d2 = val / i;
            if (q_pow(10, d1, t) == 1) ans = min(ans, d1);
            if (q_pow(10, d2, t) == 1) ans = min(ans, d2);
        }
    }

    printf("Case %d: %lld\n", idx, ans);
}

int main() {
   
    ios::sync_with_stdio(false);
    cin.tie(0);

    init(N - 1);
    int T = 1;
    while (cin >> L, L) solve(T++);

    return 0;
}