Vibe Coding坠机了,稍微手修了一下.

User

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
元素因数之和
给定正整数集合E,如果E的一个元素x能整除E的另一个元素,则称x为E的元素因数。

E的所有元素因数之和记作sev(E)。
例如,sev({1,2,5,6})=1+2=3。

记S(n)为{1,2,...,n}的所有子集E对应的sev(E)之和。
已知S(10)=4927


求S(10^14)mod 1234567891。

我的思路:对于一个数x,这个集合里面有 \lfloor \frac nx\rfloor -1个元素是这个数字能整除的,这些元素至少出现一个,也就是(x出现的所有情况)-(x出现但所有这些数字都不出现)的情况数,剩下的 n-\lfloor \frac nx\rfloor个元素无所谓,也就是上面再乘上 2^{n-\lfloor \frac nx\rfloor},再乘上这个数字x,最后加起来即可.

请给我对应的c++实现.

GPT

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
下面给出**严谨推导 + 可直接使用的高效 C++ 实现(可处理 n = 10¹⁴)**。

---

# ✅ 数学推导(与你的思路一致)

对每个 (x\in[1,n]),若想让 (x) 对贡献到 (sev(E)),必须满足:

1. (x\in E)
2. 存在某个 (k>1),使得 (kx\in E)


[
m = \left\lfloor\frac{n}{x}\right\rfloor
]
则:

* (x) 的倍数是:(x,2x,3x,\ldots, mx)(共有 m 个)
* 除了 (x) 之外,可用于“使 x 成为元素因数”的元素数为:(m-1)
* 集合中剩余可自由出现的元素个数:(n-m)

---

## 贡献计数

包含 (x) 的子集数为:

[
2^{n-1}
]

包含 (x),但**所有倍数 (2x,3x,\ldots,mx) 都不出现**的子集数为:

[
2^{n-m-1}
]

因此:
使 (x) 成为元素因数的集合数为:

[
C_x = 2^{n-1} - 2^{n-m-1}
]

贡献:

[
\text{contrib}_x = x\cdot C_x
]

总和:

[
S(n)=\sum_{x=1}^{n} x\left(2^{,n-1} - 2^{,n-\lfloor n/x\rfloor -1}\right)
]

显然不能对 x 一一遍历(n=10¹⁴),但 **m = ⌊n/x⌋ 只有 O(√n) 种取值**,可用分块(整除分块)优化。

---

# 🔥 最终 C++ 实现(支持 n=10¹⁴)

* 使用整除分块求所有相同 (m=\lfloor n/x\rfloor) 的 x 区间
* 预处理快速幂
* 使用等差数列求和计算 (\sum x)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <bits/stdc++.h>
using namespace std;

using int64 = long long;
const long long MOD = 1234567891;

// a^b % mod
long long modpow(long long a, long long b) {
long long r = 1;
while (b) {
if (b & 1) r = (__int128)r * a % MOD;
a = (__int128)a * a % MOD;
b >>= 1;
}
return r;
}

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

long long n;
cin >> n; // 输入 n = 1e14

long long P = modpow(2, n - 1); // 2^(n-1)
long long ans = 0;

long long x = 1;
while (x <= n) {
long long m = n / x; // 当前段的 floor(n/x)
long long r = n / m; // 该 m 对应的 x 区间为 [x, r]

// sum_x = x + (x+1) + ... + r
long long cnt = r - x + 1;
long long sum_x = (__int128)(x + r) * cnt / 2 % MOD;

long long term = (P - modpow(2, n - m - 1) + MOD) % MOD;
long long contrib = (__int128)sum_x * term % MOD;

ans = (ans + contrib) % MOD;

x = r + 1;
}

cout << ans % MOD << "\n";
return 0;
}
1
2
3
4
5
---

# 📌 使用方式

在输入:
1
100000000000000
1
即可输出:
1
S(10^14) mod 1234567891
1
2
3
4
5
6
7
8
9
10
---

# 如果你需要

✅ 推导的更详细分步
✅ 我帮你跑出实际输出结果
✅ 换 Python 版本
✅ 优化方法讲解(例如进一步减少 modpow 调用)

都可以继续问我!

fun fact

手修.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <bits/stdc++.h>
using namespace std;

using int64 = long long;
const long long MOD = 1234567891;

// a^b % mod
long long modpow(long long a, long long b) {
long long r = 1;
while (b>0) {//这里gpt写成b,死循环了
if (b & 1) r = (__int128)r * a % MOD;
a = (__int128)a * a % MOD;
b >>= 1;
}
return r;
}


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

long long n;
cin >> n; // 输入 n = 1e14

long long P = modpow(2, n - 1); // 2^(n-1)
long long ans = 0;

long long x = 1;
int ccnt=0;
while (x<=n) {
long long m = n / x; // 当前段的 floor(n/x)
long long r = n / m; // 该 m 对应的 x 区间为 [x, r]
// cout<<x<<" "<<r<<"\n";
// sum_x = x + (x+1) + ... + r
long long cnt = r - x + 1;
long long sum_x = (x + r) * (__int128)cnt / 2 % MOD;

long long term = ((P - modpow(2, n - m)) % MOD+MOD)%MOD;//这里写成n-m-1了,不对
long long contrib = (__int128)sum_x * term % MOD;

ans = (ans + contrib) % MOD;

x = r + 1;
}
// cout<<"! "<<n<<"\n";
cout << (ans % MOD) << "\n";
return 0;
}