欧拉计划 21 ~ 30

21

我们需要实现线性筛因数和 \(\sigma(n)\),这一点是可以办到的。

由算数基本定理可知:\(n = p_1^{\alpha_1}p_2^{\alpha_2}\ldots p_k^{\alpha_k}\),而 \(\sigma(n) = (1 + p_1 + \cdots + p_1^{\alpha_1})\ldots(1 + p_k + \cdots + p_k^{\alpha_k})\)

\(p[i]\) 表示 \(i\) 中最小质因子的等比数列和,\(d[i]\) 表示 \(\sigma(i)\),则由线性筛的性质可知:

  • \(isprime(i) = 1\),则 \(p[i] = d[i] = i + 1\) 显然。

  • \(i \bmod primes[j] \neq 0\),则该质数之前从未出现过,由于我们从小到大枚举质数,所以可以做如下更新:

\[\begin{aligned}&d[i * primes[j]] = d[primes[j]] * d[i] + 1 \\ &p[i * primes[j]] = primes[j] + 1\end{aligned} \]

  • \(i \bmod primes[j] = 0\),该质数以前出现过,所以我们做如下更新:

\[\begin{aligned}&d[i * primes[j]] = d[i] / p[i] * (p[i] * primes[j] + 1) \\ &p[i * primes[j]] = p[i] * primes[j] + 1 \end{aligned} \]

注意顺序,结果判断 \(d[d[i]] = i\)\(i \neq d[i]\) 即可。

// cpp
#include<bits/stdc++.h>
using namespace std;
const int N = 10010;
int st[N], primes[N], d[N], p[N], cnt;

int main() {
    d[1] = 1;
    for (int i = 2; i < N; i ++ ) {
        if (!st[i]) p[i] = d[i] = i + 1, primes[cnt ++ ] = i;
        for (int j = 0; i * primes[j] < N; j ++ ) {
            st[i * primes[j]] = 1;
            if (i % primes[j] == 0) {
                d[i * primes[j]] = d[i] / p[i] * (p[i] * primes[j] + 1);
                p[i * primes[j]] = p[i] * primes[j] + 1;
                break;
            }
            d[i * primes[j]] = d[i] * d[primes[j]];
            p[i * primes[j]] = primes[j] + 1;
        }
    }
    for (int i = 1; i < N; i ++ ) d[i] -= i;
    int n = 10000, ans = 0;
    for (int i = 1; i <= n; i ++ ) {
        if (d[i] != i && i == d[d[i]]) {
            ans += i;
        }
    }
    cout << ans;
    return 0;
}

22

# python
form = [xxx.txt] // TOOOOO LONG
form = sorted(form)
ans = 0
i = 1
for s in form:
    sum = 0
    for c in s:
        sum += ord(c) - ord('A') + 1
    sum *= i
    i += 1
    ans += sum
print(ans)

23

筛出 \(28123\) 以内的盈数,两两相加覆盖即可,最后统计未被覆盖的数的个数。

// cpp
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int primes[N], d[N], p[N], cnt;
bool st[N];
int dp[N];
int n = 28123;

int main() {
    for (int i = 2; i <= n; i ++ ) {
        if (!st[i]) primes[cnt ++ ] = i, d[i] = p[i] = i + 1;
        for (int j = 0; primes[j] * i <= n; j ++ ) {
            st[i * primes[j]] = 1;
            if (i % primes[j] == 0) {
                d[i * primes[j]] = d[i] / p[i] * (p[i] * primes[j] + 1);
                p[i * primes[j]] = p[i] * primes[j] + 1;
                break;
            }
            d[i * primes[j]] = d[i] * d[primes[j]];
            p[i * primes[j]] = primes[j] + 1;
        }
    }
    for (int i = 2; i <= n; i ++ ) d[i] -= i;
    vector<int> num;
    for (int i = 2; i <= n; i ++ ) {
        if (d[i] > i) {
            num.push_back(i);
        }
    }
    unordered_map<int, int> mp;
    for (int i = 0; i < num.size(); i ++ ) {
        for (int j = i; j < num.size(); j ++ ) {
            if (num[i] + num[j] > n) break;
            mp[num[i] + num[j]] = 1;
        }
    }
    int ans = 0;
    for (int i = 1; i <= n; i ++ ) ans += mp[i] ? 0 : i;
    cout << ans;
    return 0;
}

24

本题考察了 康拓展开 的计算。

\[X = a_n(n - 1)! + a_{n - 1}(n - 2)! + \cdots + a_1 \]

其中 \(a_i\) 为原数第 \(i\) 位在未出现的数字中的排名。

比如 \(52413\) 的第一位是 \(5\),贡献为 \(5 \times 4!\),第二位是 \(2\),贡献为 \(2 \times 3!\),第三位为 \(4\),由于后面没出现的数只有 \(1, \, 3, \, 4\) 了,所以它的贡献为 \(3 \times 2!\),同理第四位 \(1\) 的贡献为 \(1 \times 1!\),第五位 \(0\) 的贡献为 \(1 \times 0!\),所以:

\[X_{52413} = 5\times 4! + 2 \times 3! + 3 \times 2! + 1 \times 1! + 1 \times 0! \]

求原排列只用进行康拓展开的逆运算即可。

# python
from sympy import *
num = []
for i in range(10):
    num.append(i)
A = 1e6 - 1
ls = []
for i in range(10):
    cnt = A // factorial(9 - i)
    A = A % factorial(9 - i)
    ls.append(num[cnt])
    num.remove(num[cnt])
for i in ls:
    print(i, end='')

25

# python
cnt = 1
a = "1"
b = "1"
while len(a) < 1000:
    c = int(a) + int(b)
    a = b
    b = str(c)
    cnt += 1
print(cnt)

26

定理:一个数的因数只含 \(2, \, 5\) 的倍数,这个数一定是有限小数,否则一定是无限循环小数,这个是很好证的。

其中只含 \(2, 5\) 因子分母的分数叫 有限小数,不含 \(2, \, 5\) 因子的分母的分数叫 纯循环小数,其余的叫 混循环小数

不妨来证明一下:

  • \(n\) 为质数

我们如果要 \(\frac{1}{n}\) 有循环,必然有 \(\left\{\frac{10^k}{n}\right\} = \left\{\frac{1}{n}\right\}\)

那么显然满足同余方程 \(10^k \equiv 1 \pmod n\)

考虑 \(2, \, 5\)\(10\) 的因数,所以取模后为 \(0\),因此 \(\frac{1}{2}\)\(\frac{1}{5}\) 必然是有限的,根据 算数基本定理,其余的数一定取模后不余 \(0\),否则其唯一分解中含有 \(2, \, 5\) 因子,同时,它们还满足 费马小定理 因此在 \(n - 1\) 内必然有解。

事实上,不含 \(2, \, 5\) 因子的数都可以通过 欧拉定理 推断出 \(\varphi(n)\) 内有解。

  • \(n\) 为合数

在模 \(n\) 的剩余系中,\(10^k\) 具有一个阶,这个阶的大小不超过 \(\varphi(n)\),这是 欧拉定理 告诉我们的。

此时不一定满足 \(\left\{\frac{10^k}{n}\right\} = \left\{\frac{1}{n}\right\}\),但满足 \(\left\{\frac{10^{k + m}}{n}\right\} = \left\{\frac{10^k}{n}\right\}\)

我们称 \(m\)\(10\) 关于模 \(n\) 剩余系的 ,也就是我们的循环位数,如果我们改写上式可以得到

\[10^k(10^m - 1) \equiv 0 \pmod n \]

显然取充分大的 \(k\) 依旧满足上式,那么这个式子实际上就与 \(2, \, 5\) 因子没有任何关系了。

因为 \(n \mid 10^k(10^m - 1)\),记 \(d = \gcd(n, \, 10^k), \, n = dn'\),则

\[n' \mid (10^m - 1) \]

等价于 \(10^m \equiv 1 \pmod{n'}\),这和我们前者完全一致,因此我们只需要消去 \(n\)\(2, \, 5\) 因子,找到满足上述同余方程的最小 \(m\) 即可。

综上,可以写出相对来说简单的代码。

# python
from sympy import *
ans = 1
num = 1
for i in range(2, 1000):
    j = 1
    t = i
    while t % 2 == 0: t //= 2
    while t % 5 == 0: t //= 5
    while pow(10, j, t) != 1: j += 1
    if ans < j and pow(10, j, t) == 1:
        ans = j
        num = i
print(num)

27

# python
from sympy import *
ans = 0
a = 0
b = 0
for i in range(-1000, 1001):
    for j in range(-1000, 1001):
        if i + 1 + j <= 0: continue
        for k in range(1, 100):
            if not isprime(k * k + i * k + j):
                if ans < k - 1:
                    ans = k - 1
                    a = i
                    b = j
                break
print(a * b)

28

197-196-195-194-193-192-191-190-189-188-187-186-185-184-183
  |                                                       |
198 145-144-143-142-141-140-139-138-137-136-135-134-133 182
  |   |                                               |   |
199 146 101-100--99--98--97--96--95--94--93--92--91 132 181
  |   |   |                                       |   |   |
200 147 102  65--64--63--62--61--60--59--58--57  90 131 180
  |   |   |   |                               |   |   |   |
201 148 103  66  37--36--35--34--33--32--31  56  89 130 179
  |   |   |   |   |                       |   |   |   |   |
202 149 104  67  38  17--16--15--14--13  30  55  88 129 178
  |   |   |   |   |   |               |   |   |   |   |   |
203 150 105  68  39  18   5---4---3  12  29  54  87 128 177
  |   |   |   |   |   |   |       |   |   |   |   |   |   |
204 151 106  69  40  19   6   1---2  11  28  53  86 127 176
  |   |   |   |   |   |   |           |   |   |   |   |   |
205 152 107  70  41  20   7---8---9--10  27  52  85 126 175
  |   |   |   |   |   |                   |   |   |   |   |
206 153 108  71  42  21--22--23--24--25--26  51  84 125 174
  |   |   |   |   |                           |   |   |   |
207 154 109  72  43--44--45--46--47--48--49--50  83 124 173
  |   |   |   |                                   |   |   |
208 155 110  73--74--75--76--77--78--79--80--81--82 123 172
  |   |   |                                           |   |
209 156 111-112-113-114-115-116-117-118-119-120-121-122 171
  |   |                                                   |
210 157-158-159-160-161-162-163-164-165-166-167-168-169-170
  |
211-212-213-214-215-216-217-218-219-220-221-222-223-224-225

通过找规律不难发现,计算和 \(1\) 同一列的元素的两倍即可,

# python
from sympy import *
ans = 0
for n in range(1, 501, 1):
    ans += 4 * n * n + 3 * n + 1
    ans += 4 * n * n - 9 * n + 6
print(ans * 2 + 1)

29

python 发力了,常规做法需要筛质因数,然后进行判断,比较复杂,发现数据较小,所以利用 python 大数计算的优势直接算就行了。

# python
from sympy import *
ans = []
for a in range(2, 101):
    for b in range(2, 101):
        t = pow(a, b)
        if t not in ans:
            ans.append(t)
print(len(ans))

30

显然,最大的数不会太大,\(9^5 \times 5 < 10^6\),所以在这个范围内筛即可。

注意,\(1\) 不在范围内。

# python
ans = 0
for i in range(1000000):
    x = i
    sum = 0
    while x > 0:
        sum += pow(x % 10, 5)
        x //= 10
    if sum == i:
        ans += i
print(ans - 1)
posted @ 2025-03-15 12:04  YipChip  阅读(20)  评论(0)    收藏  举报