#P3755. 第1题-数三元组
-
1000ms
Tried: 20
Accepted: 12
Difficulty: 4
所属公司 :
米哈游
时间 :2025年9月21日
-
算法标签>暴力枚举
第1题-数三元组
解题思路
设三元组为 a<b<c。因为 lcm(a,b,c) 一定是 c 的倍数,记 lcm(a,b,c)=k⋅c。又有
a+b+c≤(c−2)+(c−1)+c=3c−3<3c.题意要求 c<lcm(a,b,c)<a+b+c<3c,于是只能 k=2,即
lcm(a,b,c)=2c.因此原不等式等价为两条简单条件:
- 上界: lcm(a,b,c)=2c<a+b+c⟺a+b>c;
- 可整除: a∣2c 且 b∣2c(因 lcm(a,b,c) 是 a,b,c 的公倍数且不超过 2c)。
并且一旦 a+b>c,就自动排除了“a∣c 且 b∣c”导致 lcm=c 的情形(此时必有 a+b<c)。 结论: 在 a<b<c 下,原条件充要等价于
2cmoda=0 ∧ 2cmodb=0 ∧ a+b>c.算法(仅做整除与不等式判断,无需 gcd/lcm):
-
枚举 c∈[l+2,r],再枚举 a∈[l,c−2]。由 a+b>c⇒b>c−a,故
b 从 max(a+1,c−a+1) 到 c−1. -
对每组 (a,b,c) 检查
2c%a==0 && 2c%b==0即可(枚举已保证 a+b>c)。
复杂度分析
- 设 n=r−l+1(≤100)。三重枚举带剪枝,最坏约 O(n3) 次常数判断。
- 时间复杂度:O(n3);空间复杂度:O(1)。
代码实现
Python
import sys
def count_triples(l, r):
ans = 0
for c in range(l + 2, r + 1): # c 至少比 a 大 2
two_c = 2 * c
for a in range(l, c - 1):
# 由 a+b>c => b > c-a,同时需 b>a
b_start = max(a + 1, c - a + 1)
if b_start >= c:
continue
for b in range(b_start, c):
# 等价条件:a|2c 且 b|2c(a+b>c 已由枚举保证)
if two_c % a == 0 and two_c % b == 0:
ans += 1
return ans
def main():
data = sys.stdin.read().strip().split()
t = int(data[0])
idx = 1
out = []
for _ in range(t):
l = int(data[idx]); r = int(data[idx+1]); idx += 2
out.append(str(count_triples(l, r)))
print("\n".join(out))
if __name__ == "__main__":
main()
Java
import java.util.*;
public class Main {
// 统计满足条件的三元组数量
static long countTriples(int l, int r) {
long ans = 0;
for (int c = l + 2; c <= r; c++) {
int twoC = 2 * c;
for (int a = l; a <= c - 2; a++) {
// a+b>c 且 b>a -> b >= max(a+1, c-a+1)
int bStart = Math.max(a + 1, (c - a) + 1);
if (bStart >= c) continue;
for (int b = bStart; b <= c - 1; b++) {
// 等价条件:a|2c 且 b|2c
if (twoC % a == 0 && twoC % b == 0) {
ans++;
}
}
}
}
return ans;
}
public static void main(String[] args) {
// 数据范围很小,Scanner 足够
Scanner sc = new Scanner(System.in);
int t = sc.nextInt();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < t; i++) {
int l = sc.nextInt(), r = sc.nextInt();
sb.append(countTriples(l, r)).append('\n');
}
System.out.print(sb.toString());
sc.close();
}
}
C++
#include <bits/stdc++.h>
using namespace std;
// 统计满足条件的三元组数量
long long count_triples(int l, int r) {
long long ans = 0;
for (int c = l + 2; c <= r; ++c) {
int two_c = 2 * c;
for (int a = l; a <= c - 2; ++a) {
// a+b>c 且 b>a -> b 从 max(a+1, c-a+1) 到 c-1
int b_start = max(a + 1, (c - a) + 1);
if (b_start >= c) continue;
for (int b = b_start; b <= c - 1; ++b) {
if (two_c % a == 0 && two_c % b == 0) {
++ans;
}
}
}
}
return ans;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
if (!(cin >> t)) return 0;
while (t--) {
int l, r;
cin >> l >> r;
cout << count_triples(l, r) << "\n";
}
return 0;
}
题目内容
给定两个正整数 l 和 r ,请统计满足以下条件的 三元组 (a,b,c) 的个数:
-
l≤a<a<b<c≤r
-
max(a,b,c)<lcm(a,b,c)<sum(a,b,c)
【名词解释】
- 最大值:对于一组整数,它们的最大值记作 max(⋅) 。
- 最小公倍数:对于一组整数,能够被它们全部整除的最小正整数,记作 lcm(⋅) 。
- 和:对于一组整数,它们的和,记作 sum(⋅) 。
输入描述
第一行输入整数 t(1≤t≤10),表示测试用例数; 接下来 t 行,每行输入两个整数 l 和 r(1≤l≤r≤100,r−l+1≥3),表示区间端点。
输出描述
对于每个测试用例,在一行输出一个整数,表示满足条件的三元组个数。
样例1
输入
3
1 10
3 5
1 100
输出
1
0
22
说明
在第一个测试用例中,符合条件的三元组有 (3,4,6) ,其 max(3,4,6)=6,lcm(3,4,6)=12,sum(3,4,6)=13 ,满足条件;
在第二个测试用例中,没有符合条件的三元组。