import java.util.*;
import java.io.*;
public class Main {
static class Function {
int k, a;
Function(int k, int a) {
this.k = k;
this.a = a;
}
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int T = Integer.parseInt(br.readLine().trim());
while (T-- > 0) {
String[] line = br.readLine().split(" ");
int n = Integer.parseInt(line[0]);
int l = Integer.parseInt(line[1]);
int r = Integer.parseInt(line[2]);
long S = 0;
List<Function> list = new ArrayList<>();
for (int i = 0; i < n; i++) {
line = br.readLine().split(" ");
int k = Integer.parseInt(line[0]);
int a = Integer.parseInt(line[1]);
int b = Integer.parseInt(line[2]);
S += b;
if (k == 0) {
S += Math.abs(a);
} else {
list.add(new Function(k, a));
}
}
int m = list.size();
if (m == 0) {
bw.write(S + "\n");
continue;
}
Collections.sort(list, (f1, f2) -> {
long left = (long) (-f1.a) * f2.k;
long right = (long) (-f2.a) * f1.k;
return Long.compare(left, right);
});
long totalK = 0;
long totalKC = 0;
for (Function func : list) {
totalK += func.k;
totalKC -= func.a;
}
long[] prefixW = new long[m];
long[] prefixC = new long[m];
prefixW[0] = list.get(0).k;
prefixC[0] = -list.get(0).a;
for (int i = 1; i < m; i++) {
prefixW[i] = prefixW[i - 1] + list.get(i).k;
prefixC[i] = prefixC[i - 1] - list.get(i).a;
}
int low = l, high = r;
long ans = Long.MAX_VALUE;
while (high - low > 2) {
int mid1 = low + (high - low) / 3;
int mid2 = high - (high - low) / 3;
long f1 = F(mid1, list, prefixW, prefixC, totalK, totalKC, S);
long f2 = F(mid2, list, prefixW, prefixC, totalK, totalKC, S);
if (f1 < f2) {
high = mid2 - 1;
} else if (f1 > f2) {
low = mid1 + 1;
} else {
low = mid1 + 1;
high = mid2 - 1;
}
}
for (int x = low; x <= high; x++) {
long fx = F(x, list, prefixW, prefixC, totalK, totalKC, S);
if (fx < ans) ans = fx;
}
bw.write(ans + "\n");
}
bw.flush();
}
private static long F(int x, List<Function> list, long[] prefixW, long[] prefixC, long totalK, long totalKC, long S) {
int low = 0, high = list.size() - 1;
int pos = -1;
while (low <= high) {
int mid = (low + high) >>> 1;
Function func = list.get(mid);
if ((long) func.a >= -(long) x * func.k) {
pos = mid;
low = mid + 1;
} else {
high = mid - 1;
}
}
long sum_left_k = (pos == -1) ? 0 : prefixW[pos];
long sum_left_kc = (pos == -1) ? 0 : prefixC[pos];
long F1 = (long) x * (2 * sum_left_k - totalK) + (totalKC - 2 * sum_left_kc);
return F1 + S;
}
}
https://www.nowcoder.com/discuss/727521113110073344
思路:
- 常数处理:当 𝑘𝑖=0 时,函数为常数,直接加入总和 𝑆。
- 排序:对 𝑘𝑖>0 的函数按 𝑐𝑖=−𝑎𝑖/𝑘𝑖 排序,使用交叉相乘避免浮点数精度问题。
- 前缀和:计算权重和 𝑝𝑟𝑒𝑓𝑖𝑥𝑊 及常数和 𝑝𝑟𝑒𝑓𝑖𝑥𝐶 的前缀数组,用于快速计算 𝐹(𝑥)。
- 三分搜索:利用凸函数性质,在区间 [𝑙,𝑟] 上三分查找最小值点。
- 二分定位:对每个 𝑥,二分查找满足 𝑐𝑖≤𝑥 的最大位置,使用前缀和公式高效计算函数值。



京公网安备 11010502036488号