Vibe Coding再次翻车.

User

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
解不定方程1/a+1/b= p/{10^n}

考虑不定方程1/a+1/b= p/{10^n},其中a, b, p, n均为正整数,且a ≤ b。
对于n=1,这个方程有20个解,如下所示:


1/1+1/1=20/10 1/1+1/2=15/10 1/1+1/5=12/10 1/1+1/10=11/10 1/2+1/2=10/10
1/2+1/5=7/10 1/2+1/10=6/10 1/3+1/6=5/10 1/3+1/15=4/10 1/4+1/4=5/10
1/4+1/20=3/10 1/5+1/5=4/10 1/5+1/10=3/10 1/6+1/30=2/10 1/10+1/10=2/10
1/11+1/110=1/10 1/12+1/60=1/10 1/14+1/35=1/10 1/15+1/30=1/10 1/20+1/20=1/10
对于1 ≤ n ≤ 9,方程一共有多少个解?

我的思路:直接搜索.
注意到左侧的数字a的范围是很有限的,最大也就是2*10^n,那么固定左侧a检查右侧b存不存在即可.
我给你一个简易的分数类,请给我这个题的c++实现.
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
struct divisor{//假分数
__int128 upper,lower,num;
divisor(__int128 a=0,__int128 b=1,__int128 c=0):upper(a),lower(b),num(c){}
divisor operator +(const divisor& io)const{
divisor res;
res.upper=upper*io.lower+lower*io.upper;
res.lower=lower*io.lower;
__int128 tmp=__gcd(res.upper,res.lower);
// assert(tmp!=0);
res.upper/=tmp;
res.lower/=tmp;
res.num=(num+io.num+((res.upper)/(res.lower)));
res.upper%=res.lower;
return res;
}
divisor operator *(const divisor& io)const{
divisor res;
res.upper=num*lower*io.upper+io.num*upper*io.lower+upper*io.upper;
res.lower=lower*io.lower;
__int128 tmp=__gcd(res.upper,res.lower);
assert(tmp!=0);
res.upper/=tmp;
res.lower/=tmp;
res.num=(num+io.num+(res.upper/res.lower));
res.upper%=res.lower;
return res;
}
int lenth(__int128 tmp){
int len=0;
if(tmp<=0){len++;tmp=-tmp;}
while(tmp>0){
len++;
tmp/=10;
}
return len;
}
void prr(){
if(upper!=0){
int sp=lenth(num);
int sl=max(lenth(upper),lenth(lower));
for(int i=1;i<=sp;++i){
fout<<" ";
}
fout<<upper<<"\n";
fout<<num;
for(int i=1;i<=sl;++i){
fout<<"-";
}enter;
for(int i=1;i<=sp;++i){
fout<<" ";
}
fout<<lower;
}else{
fout<<num;
}
}
};

DeepSeek

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
好的,我们先来分析一下这个题,然后我会给出一个高效的 C++ 解法,不需要用到你给出的复杂分数类。

---

## 问题重述

我们要求解方程:

\[
\frac{1}{a} + \frac{1}{b} = \frac{p}{10^n}
\]
其中:
- \( a, b, p, n \) 均为正整数
- \( a \le b \)
- \( n \) 从 1 到 9
- 需要统计每个 \( n \) 下方程有多少个解。

---

## 数学变换

原方程:
\[
\frac{1}{a} + \frac{1}{b} = \frac{p}{10^n}
\]
两边乘以 \( ab \cdot 10^n \):
\[
10^n (b + a) = p \cdot a \cdot b
\]
这里 \( p \) 也是正整数,由等式左边是正整数可知 \( p \) 自动满足,但我们不需要显式求出 \( p \),只需要判断 \( a, b \) 能否让右边为正整数即可。

更直接的推导:


\[
\frac{1}{a} + \frac{1}{b} = \frac{p}{10^n}
\]
那么
\[
\frac{a+b}{ab} = \frac{p}{10^n}
\]

\[
10^n (a+b) = p \cdot ab
\]
这说明 \( 10^n (a+b) \) 能被 \( ab \) 整除,即
\[
ab \mid 10^n (a+b)
\]
或者更具体地,\( p = \frac{10^n (a+b)}{ab} \) 必须是正整数。

---

## 求解条件

已知 \( a, b \) 为正整数,\( a \le b \),则 \( p = \frac{10^n (a+b)}{ab} \) 为正整数。

等价于:
\[
ab \mid 10^n (a+b)
\]

设 \( d = \gcd(a,b) \),\( a = d x \),\( b = d y \),其中 \( \gcd(x,y)=1 \),且 \( x \le y \)。

代入:
\[
p = \frac{10^n (d x + d y)}{d^2 x y} = \frac{10^n (x+y)}{d x y}
\]
因为 \( \gcd(x,y)=1 \),所以 \( \gcd(x+y, xy) = 1 \)(可以证明:若质数 \( q \mid x \) 且 \( q \mid x+y \) 则 \( q \mid y \),矛盾;同理对 \( y \))。

因此要使 \( p \) 为整数,必须有
\[
d \mid \frac{10^n (x+y)}{?}
\]
等等,更严谨一点:

\( p \) 为整数 \(\iff\) \( d x y \mid 10^n (x+y) \)。

因为 \( \gcd(xy, x+y) = 1 \),所以条件变为:
\[
d \mid \frac{10^n (x+y)}{x y} \ \text{且必须整除?}
\]
不对,我们直接看:\( d x y \mid 10^n (x+y) \)。

由于 \( \gcd(xy, x+y)=1 \),所以 \( xy \mid 10^n \) 必须成立,否则 \( d \) 再怎么取也除不尽。

因此**关键条件**:
\[
xy \mid 10^n
\]
因为 \( \gcd(x,y)=1 \),\( xy \mid 10^n = 2^n \cdot 5^n \),所以 \( x \) 和 \( y \) 都必须是 \( 2^a 5^b \) 的形式,且互质。

然后 \( d \) 的取值由:
\[
d \mid \frac{10^n (x+y)}{xy}
\]
更确切地说,\( p = \frac{10^n (x+y)}{d xy} \) 为正整数 \(\iff\) \( d \) 是 \( \frac{10^n (x+y)}{xy} \) 的约数。

---

## 枚举方法

我们枚举 \( x, y \):
- \( x \le y \)
- \( \gcd(x,y)=1 \)
- \( xy \mid 10^n \),即 \( x = 2^{a1} 5^{b1} \),\( y = 2^{a2} 5^{b2} \),且 \( a1+a2 \le n \),\( b1+b2 \le n \),同时 \( \gcd(x,y)=1 \) 意味着 \( \min(a1,a2)=0 \) 且 \( \min(b1,b2)=0 \)。

对每一对 \((x,y)\),令
\[
T = \frac{10^n (x+y)}{xy} = 10^n \cdot \frac{x+y}{xy}
\]
那么 \( d \) 可以取 \( T \) 的任意正约数(因为 \( d \) 是正整数,且 \( p = T/d \) 为正整数)。

对每个 \( d \),我们有:
\[
a = dx, \quad b = dy
\]
需要满足 \( a \le b \)(自动满足,因为 \( x \le y \))。

因此**每一对 \((x,y)\) 给出的解的数量** = \( T \) 的正约数个数。

---

## 算法步骤

1. 对每个 \( n \),生成所有互质的 \((x,y)\) 满足 \( xy \mid 10^n \),且 \( x \le y \)。
2. 对每个这样的 \((x,y)\),计算 \( T = 10^n \cdot (x+y) / (xy) \)。
3. 求 \( T \) 的约数个数,累加到答案。

注意:直接枚举 \( x, y \) 作为 \( 2^a 5^b \) 形式即可,因为条件 \( xy \mid 10^n \) 意味着它们只能有质因子 2 和 5,且互质意味着指数不能同时为正。

---

## C++ 实现

我们不需要复杂的分数类,因为这里所有计算都是整数。
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
66
67
68
69
70
71
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <numeric>
#include <cstdint>
using namespace std;

using ll = long long;
using ull = unsigned long long;

// 枚举所有形如 2^a * 5^b 的数 <= 10^n
vector<ll> gen_numbers(int n) {
vector<ll> res;
ll max_val = pow(10, n);
for (int a = 0; a <= n; ++a) {
ll p2 = 1;
for (int i = 0; i < a; ++i) p2 *= 2;
for (int b = 0; b <= n; ++b) {
ll p5 = 1;
for (int i = 0; i < b; ++i) p5 *= 5;
ll val = p2 * p5;
if (val <= max_val) {
res.push_back(val);
} else {
break;
}
}
}
sort(res.begin(), res.end());
res.erase(unique(res.begin(), res.end()), res.end());
return res;
}

// 计算 num 的正约数个数
int count_divisors(ll num) {
int cnt = 0;
for (ll i = 1; i * i <= num; ++i) {
if (num % i == 0) {
cnt++;
if (i * i != num) cnt++;
}
}
return cnt;
}

int main() {
ll pow10[10];
pow10[0] = 1;
for (int i = 1; i <= 9; ++i) pow10[i] = pow10[i-1] * 10;

for (int n = 1; n <= 9; ++n) {
vector<ll> nums = gen_numbers(n); // 所有 2^a*5^b 且 <= 10^n
ll total = 0;

// 枚举互质对 (x, y)
for (size_t i = 0; i < nums.size(); ++i) {
ll x = nums[i];
for (size_t j = i; j < nums.size(); ++j) { // x <= y
ll y = nums[j];
if (gcd(x, y) != 1) continue;
// 检查 xy 是否整除 10^n
if ((pow10[n] % (x * y)) != 0) continue; // 其实这里 nums 生成时已经保证 xy | 10^n
ll T = (pow10[n] / (x * y)) * (x + y);
total += count_divisors(T);
}
}
cout << "n = " << n << ": " << total << " solutions" << endl;
}
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---

## 说明

- `gen_numbers(n)` 生成所有 \( \le 10^n \) 的 \( 2^a 5^b \) 形式的数,这正好是 \( xy \mid 10^n \) 的候选 \( x, y \)。
- 枚举时检查 `gcd(x,y)=1` 和 `xy | 10^n`(其实第二个条件自动满足,因为生成的数都是 10^n 的约数,且乘起来 ≤ 10^n,这里为了保险保留检查)。
- 对每个 \((x,y)\) 计算 \( T \) 并求其约数个数,累加即可。

这样可以得到 \( n = 1 \) 到 \( 9 \) 的解的数量。

---

## 验证 n=1

用这个程序跑一下,\( n=1 \) 应该输出 20,和你给出的例子一致。

---

**总结**:我们通过数学推导将问题转化为枚举互质的 2^a5^b 形式的数对,然后计算一个表达式的约数个数,从而高效求解,避免了直接枚举 a, b 到 2*10^n 的大规模循环。

fun fact

GPT TLE了,不知道在搜索什么.
DeepSeek-v一发过了.
Flu给的做法完全是假的,Flu以为是求1/a+1/b=1/10^n,结果是p/10^n,做法作假,Vibe Coding翻车了.

保真的做法:首先合并ab,发现10^n(a+b)/ab是个正整数.
所以ab是整除10^n的,首先枚举这样的对,然后检查这些对的倍数是否满足.