「TFOI R1」Average Number 题解

出题人题解。

原本预估的难度是黄,但是从反馈来看的话难度是绿(


题意应该很清楚,我的解法是推式子+缩放,一些奇怪的方法可以看 Super_Cube 的题解

$$ \begin{aligned} &\dfrac{\dfrac{n \times (n + 1)}{2} - m}{n - 1}\\ =&\dfrac{n \times (n + 1) - 2 \times m}{2 \times (n - 1)}\\ =&\dfrac{n \times (n - 1) + 2 \times n - 2 \times m}{2 \times (n - 1)}\\ =&\dfrac{n}{2} + \dfrac{n - m}{n - 1}\\ =&a + \dfrac{b}{c}\\ \end{aligned} $$

接下来是缩放,也是我认为的这一道题最精彩的部分。

注意到 $1 \leqslant m \leqslant n$,所以 $0 \leqslant n - m \leqslant n - 1$。

所以 $0 \leqslant \dfrac{n - m}{n - 1} \leqslant 1$。

带入到上面的式子后就是:

$$ \dfrac{n}{2} \leqslant \dfrac{n}{2} + \dfrac{n - m}{n - 1} = a + \dfrac{b}{c} \leqslant \dfrac{n}{2} + 1 $$

因为 $\dfrac{b}{c}$ 是最简真分数(也就是小于 $1$),所以又有:

$$ \dfrac{n}{2} - 1 < a \leqslant \dfrac{n}{2} + 1 $$

把它拆成两个不等式并化简:

$$ \begin{cases} n < 2\times a + 2\\ 2 \times a - 2 \leqslant n \end{cases} $$

(因为 $n$ 是正整数,所以 $n < 2\times a + 2$ 等价于 $n \leqslant 2\times a + 1$)

最后就得到了:$2 \times a - 2 \leqslant n \leqslant 2 \times a + 1$。

于是可以在这个范围枚举 $n$,也就带一个四倍的常数。

$n$ 得到了之后带回最初的式子就可以得到 $m$ 的值,也就是:

$$ \begin{aligned} \dfrac{\dfrac{n \times (n + 1)}{2} - m}{n - 1}&= \dfrac{a \times c + b}{c}\\ \dfrac{n \times (n + 1)}{2} - m&= \dfrac{(n - 1) \times (a \times c + b)}{c}\\ m&= \dfrac{n \times (n + 1)}{2} - \dfrac{(n - 1) \times (a \times c + b)}{c}\\ \end{aligned} $$

因为 $m$ 也是正整数,所以要检查一下 $c$ 能不能整除 $n - 1$。

要注意上面的式子算出来的 $m$ 仍然可能不合法(比如出现负数),以及 $a = 1$ 时 $2 \times a - 2 = 0$ 但是 $n \geqslant 2$ 要判断一下。

运算过程中变量可能超 long long,记得开 __int128 还有优化运算顺序。

最后给出代码:

#include <bits/stdc++.h>
using namespace std;
#define getchar gc
typedef __int128 ll;
#define fu(i, l, r) for(ll i = l; i <= r; ++i)
char gc() {static char ibuf[1 << 20], *p1 = ibuf, *p2 = ibuf; return p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, 1000010, stdin), p1 == p2) ? -1 : *p1++;}
void read(ll& x) {x = 0; int f = 1; char ch = getchar(); while(ch < '0' || ch > '9') f *= ((ch == '-') ? -1 : 1), ch = getchar(); while(ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar(); x *= f;}
ll t, m, a, b, c;
int main() {
    read(t);
    while(t--) {
        read(a), read(b), read(c);
        fu(i, max(2 * a - 2, (ll)2), 2 * a + 1) {
            if((i - 1) % c) continue;
            m = i * (i + 1) / 2 - (i - 1) / c * (a * c + b);
            if(m < 1 || m > i) continue;
            printf("%lld %lld\n", (long long)i, (long long)m);
            break;
        }
    }
    return 0;
}
posted @ 2023-10-05 15:09  A_box_of_yogurt  阅读(6)  评论(0编辑  收藏  举报  来源
Document