语言月赛 202311 方程求解
题意分析¶
给定 $n$ 个形如 $a_ix + b_i = c_i$ 的一元一次方程,小 A 想知道在每次给定的区间 $[L, R]$ 内,有多少个正整数 $x$ 是至少一个方程的解。
每次询问输出满足条件的正整数 $x$ 的个数。
解题思路¶
一、方程的处理¶
每个方程都形如:
$a\cdot x + b = c$
我们可以移项并求解:
\[
x = \frac{c - b}{a}
\]
根据题目保证,所有方程的解都是正整数,即 $\frac{c - b}{a}$ 是正整数,且结果大于等于 1。
因此我们可以:
- 遍历所有方程,提取出系数 $a, b, c$。
- 利用上述公式求出对应的 $x$。
- 将求出的所有解 $x$ 存储(例如打标记
vis[x] = 1
)。
特别说明:由于题目中字符如
x
、+
、=
并不影响求解,因此可直接略过,仅关注a, b, c
三个数值的提取与处理。
for (int i = 1; i <= n; i++)
{
int a, b, c;
char op1, op2, op3;
// 252x+578=10245
cin >> a >> op1 >> op2 >> b >> op3 >> c;
int x;
if (op2 == '+')
x = (c - b) / a;
else
x = (c + b) / a;
vis[x] = 1;
}
二、查询处理¶
接下来处理 $Q$ 次询问。每次输入一个区间 $[L, R]$,统计该区间内有多少个整数 $x$ 满足 vis[x] = 1
。
实现方式非常简单:
- 对于每个询问,从 $i = L$ 到 $R$ 遍历;
- 统计其中有多少个位置满足
vis[i] = 1
; - 统计结果即为本次询问的答案。
实现步骤¶
-
预处理阶段:
- 遍历 $n$ 个方程;
- 对每个方程解析出 $a, b, c$;
- 利用公式 $x = (c - b) / a$ 求出解;
- 若 $x$ 是正整数(即 $x \geq 1$ 且整除),则打标记:
vis[x] = 1
。
-
查询阶段:
- 对于每次询问区间 $[L, R]$:
- 初始化计数器;
- 从 $L$ 遍历到 $R$,累加
vis[i]
; - 输出计数器值。
- 对于每次询问区间 $[L, R]$:
时间复杂度分析¶
- 预处理方程:$O(n)$;
- 每次查询暴力枚举 $[L, R]$:最坏 $O(1000)$;
- 总体复杂度为 $O(n + Q \cdot 1000)$,其中 $n, Q \leq 1000$,完全可以接受。
总结¶
- 核心是将所有方程的正整数解打标记;
- 每次查询通过暴力枚举区间统计标记次数;
- 利用固定上限范围($x \leq 1000$)简化实现;
- 本题是典型的“值域有限 + 预处理 + 暴力查询”模型,非常适合入门题型练习。