1. 程式人生 > 實用技巧 >題解:P5171 Earthquake

題解:P5171 Earthquake

不會類歐的可以看這裡

列舉 \(x\),那麼合法的 \(y\) 的個數為 \(\lfloor \dfrac{c - ax}{b} \rfloor+1\)。那麼題目要求的就是:

\[\sum_{x=0}^{\lfloor \frac{c}{a} \rfloor} \lfloor \frac{c-ax}b \rfloor+1 \]

發現和類歐的唯一區別是 \(x\) 的係數是負數。但是我們可以在分子上加一個 \(bx\) 即可。這裡假設 \(b \ge a\),當 \(b < a\) 的時候可以交換 \(a,b\)

\[\begin{aligned} \sum_{x=0}^{\lfloor \frac{c}{a} \rfloor} \lfloor \frac{(b-a)x+c}{b} \rfloor - x + 1\\ = \sum_{x=0}^{\lfloor \frac{c}{a}\rfloor} \lfloor \frac{(b-a)x+c}b \rfloor - \frac{\lfloor \frac{c}{a}\rfloor (\lfloor \frac{c}{a} \rfloor + 1)}2+\lfloor \frac{c}{a} \rfloor + 1 \end{aligned} \]

然後直接用類歐算即可。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
typedef long long ll;
template <typename T> inline void read(T &x) {
	x = 0; char c = getchar(); bool flag = false;
	while (!isdigit(c)) { if (c == '-')	flag = true; c = getchar(); }
	while (isdigit(c)) { x = (x << 1) + (x << 3) + (c ^ 48); c = getchar(); }
	if (flag)	x = -x;
}
using namespace std;
inline ll sol(ll a, ll b, ll c, ll n) {
	if (!a)	return (n + 1) * (b / c);
	if (a >= c || b >= c) {
		return n * (n + 1) / 2 * (a / c) + (n + 1) * (b / c) + sol(a % c, b % c, c, n);
	}
	ll m = (a * n + b) / c;
	return n * m - sol(c, c - b - 1, a, m - 1);
}

int main() {
	ll a, b, c; read(a), read(b), read(c);
	if (b < a)	swap(b, a);
	ll res = 0;
	res += sol(b - a, c, b, c / a);
	res -= (c / a) * (c / a + 1) / 2;
	res += c / a;
	++res;
	cout << res << endl;
	return 0;
}