「解题报告」ARC123E Training

发布时间 2023-03-28 10:40:00作者: APJifengc

挺有趣的题,为数不多的自己能切的题。

题意无非就是要你求 \(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;
}