「解题报告」ARC123E Training
挺有趣的题,为数不多的自己能切的题。
题意无非就是要你求 \(i \in [1, n]\),有多少满足 \(a + \lfloor\frac{i}{b} \rfloor = c + \lfloor\frac{i}{d}\rfloor\)。
首先移项,得 \(a - c = \lfloor\frac{i}{d}\rfloor - \lfloor\frac{i}{b} \rfloor\)。
底函数没啥好分析的办法,就直接拆成不等式。
我们有 \(\alpha - 1 < \lfloor\alpha\rfloor \le \alpha\),于是上面的式子推一推就可以得到 \(a - c = \lfloor\frac{i}{d}\rfloor - \lfloor\frac{i}{b} \rfloor \in (\frac{i}{d} - \frac{i}{b} - 1, \frac{i}{d} - \frac{i}{b} + 1)\)。
此时我们发现一件事情,就是这个区间是很紧的,这个区间内最多有两个整数。因此,如果我们找出 \(i\) 的一个可能的区间,那么应当会更好统计答案。
再变换一下,把不等号反过来,就能得到 \(\frac{i}{d} - \frac{i}{b} \in (a-c-1, a-c+1), i \in (\frac{bd(a-c-1)}{b-d}, \frac{bd(a-c+1)}{b - d})\)。
此时考虑将 \(i\) 分为若干个区间来考虑。假如 \(\frac{i}{d} - \frac{i}{b} \in (a-c, a-c+1)\) 时,那么原不等式中满足条件的整数有 \(a-c, a-c+1\) 两种。同理,\(\frac{i}{d} - \frac{i}{b} \in (a-c - 1, a-c)\) 中有 \(a-c-1, a-c\),\(\frac{i}{d} - \frac{i}{b} = a-c\) 中有 \(a-c\)。
最后一个情况先判掉。那么我们可以确定每个区间中仅有两个可能的整数,而我们发现,\(\lfloor\frac{i}{a}\rfloor\) 这个函数是容易计算前缀和的。那么我们就可以计算出这个区间的和,然后解方程即可得知有多少个 \(a-c\),这便是我们要找的答案。
#include <bits/stdc++.h>
using namespace std;
int T, n, a, b, c, d;
long long sum(int n, int a) {
if (n < 0) return 0;
int b = n / a - 1, c = n % a + 1;
return 1ll * a * b * (b + 1) / 2 + 1ll * c * (b + 1);
}
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d%d%d%d%d", &n, &a, &b, &c, &d);
if (b == d) {
printf("%d\n", a == c ? n : 0);
continue;
}
if (1ll * (a - c) * (b - d) < 0) {
printf("0\n");
continue;
}
if (b < d) swap(a, c), swap(b, d);
int ans = 0;
// case 1: i(1/d-1/b) = a-c
if (1ll * b * d * (a - c) % (b - d) == 0) {
if (1ll * b * d * (a - c) / (b - d) <= n
&& 1ll * b * d * (a - c) / (b - d) >= 1)
ans++;
}
// case 2: i(1/d-1/b) \in (a-c, a-c+1)
{
long long l = min(1ll * b * d * (a - c) / (b - d) + 1, n + 1ll);
long long r = min((1ll * b * d * (a - c + 1) - 1) / (b - d), n + 0ll);
int m = r - l + 1;
int s = sum(r, d) - sum(l - 1, d) - sum(r, b) + sum(l - 1, b) - 1ll * m * (a - c);
ans += m - s;
}
// case 3: i(1/d-1/b) \in (a-c-1, a-c)
{
long long l = min(max(1ll * b * d * (a - c - 1) / (b - d) + 1, 1ll), n + 1ll);
long long r = min(max((1ll * b * d * (a - c) - 1) / (b - d), 0ll), n + 0ll);
int m = r - l + 1;
int s = sum(r, d) - sum(l - 1, d) - sum(r, b) + sum(l - 1, b) - 1ll * m * (a - c - 1);
ans += s;
}
printf("%d\n", ans);
}
return 0;
}