Loading

AGC073B 赛后补题记录

link

感觉对我而言有一定教育意义。对于这种题,感觉无从入手思考,应该马上反应过来思考归约的可能性。

\(f(a_1, a_2, \dots, a_n)\) 为答案,不失一般性令 \(a_1 = \min a_i\),那么我们有结论 \(f(a_1, a_2, \dots, a_n) = a_1 + f(a_1, a_2 - a_1, \dots, a_n - a_1)\)

考虑证明必要性和充分性。


  • 证明 \(f(a_1, a_2, \dots, a_n) \ge a_1 + f(a_1, a_2 - a_1, \dots, a_n - a_1)\)

构造满足 \(f(a_1, a_2, \dots, a_n)\) 的一条路径,一定形如 \((+, +, +, -, -, +, -, -, -, +, +, -, -, -)\) 这样。

现在考虑将其改为 \((a_1, a_2 - a_1, \dots, a_n - a_1)\),发现仍然可以通过走一个 \(a_i - a_1\) 和一个 \(a_1\) 来完成走一个 \(a_i\)

对于每一个满足一段 \(-\) 接上一段 \(+\) 的极长段 \((-, -, -, +, +, +)\),我们考虑在最后一个 \(-\) 和第一个 \(+\) 的步长减小 \(a_1\),这样就走不到 \([0, a_1 - 1]\) 中的点了。

然后在整条路经中,将第一步和最后一步减小 \(a_1\),相当于将整条路经向左平移 \(a_1\)

这样就构造出了 \(f(a_1, a_2, \dots, a_n) - a_1\),所以 \(f(a_1, a_2, \dots, a_n) \ge a_1 + f(a_1, a_2 - a_1, \dots, a_n - a_1)\),证毕。

  • 证明 \(f(a_1, a_2, \dots, a_n) \le a_1 + f(a_1, a_2 - a_1, \dots, a_n - a_1)\)

构造满足 \(f(a_1, a_2 - a_1, \dots, a_n - a_1)\) 的一条路径,现在考虑将其改为 \((a_1, a_2, \dots, a_n)\)

对于每一个满足一段 \(+\) 接上一段 \(-\) 的极长段 \((+, +, +, -, -, -)\),对于每一步 \(+x\)\(-x\),以 \(+x\) 为例,改完后应为 \(+(x + a_1)\),我们再走一步 \(-a_1\) 来修正步长。这样可以保持原来的路径,不过在最后一个 \(+\) 走的时候会超出范围,也即答案会加 \(a_1\)

这样就构造出了 \(f(a_1, a_2 - a_1, \dots, a_n - a_1) + a_1\),所以 \(f(a_1, a_2, \dots, a_n) \le a_1 + f(a_1, a_2 - a_1, \dots, a_n - a_1)\),证毕。


所以我们可以通过将 \(a_1, a_2, \dots, a_n\) 全部减去 \(\min a_i\) 来归约问题。

不妨假定 \(a_1\le a_2\le \dots \le a_n\),令 \(p = \lfloor \frac {a_2} {a_1} \rfloor a_1\)

我们令 \(a_2, a_3, \dots, a_n\) 所有数减去 \(p\),答案加上 \(p\),不断重复此过程。

可以发现该过程每进行两次,最小值至少减半:

  • \(a_2 \bmod a_1 \le \frac {a_1} 2\),显然。

  • \(a_2 \bmod a_1 > \frac {a_1} 2\),则 \(a_1 - (a_2 \bmod a_1) < a_1 - \frac {a_1} 2 = \frac {a_1} 2\)


点击查看代码
#include <bits/stdc++.h>
#define ll int
#define LL long long
#define uLL unsigned LL
#define fi first
#define se second
#define mkp make_pair
#define pir pair <ll, ll>
#define pb emplace_back
#define i128 __int128
const ll maxn = 3e5 + 10, mod = 998244353, M = 1e5, inf = 1e9;
template <class T>
void rd(T &x) {
	char ch; ll f = 0;
	while(!isdigit(ch = getchar()))
		if(ch == '-') f = 1;
	x = ch - '0';
	while(isdigit(ch = getchar()))
		x = (x << 1) + (x << 3) + ch - '0';
	if(f) x = -x;
}
ll power(ll a, ll b = mod - 2, ll p = mod) {
	ll s = 1;
	while(b) {
		if(b & 1) s = 1ll * s * a % p;
		a = 1ll * a * a % p, b >>= 1;
	} return s;
}
template <class T1, class T2>
void add(T1 &x, const T2 y) { x = x + y >= mod? x + y - mod : x + y; }
template <class T1, class T2>
void sub(T1 &x, const T2 y) { x = x < y? x + mod - y : x - y; }
template <class T1, class T2>
ll pls(const T1 x, const T2 y) { return x + y >= mod? x + y - mod : x + y; }
template <class T1, class T2>
ll mus(const T1 x, const T2 y) { return x < y? x + mod - y : x - y; }
template <class T1, class T2>
void chkmax(T1 &x, const T2 y) { x = x < y? y : x; }
template <class T1, class T2>
void chkmin(T1 &x, const T2 y) { x = x < y? x : y; }
using namespace std;

ll T, n; LL a[maxn], ans;

void solve() {
	rd(n); ans = 0;
	for(ll i = 1; i <= n; i++) rd(a[i]);
	while(a[1]) {
		LL p = a[2] / a[1] * a[1];
		ans += p;
		for(ll i = 2; i <= n; i++) a[i] -= p;
		sort(a + 1, a + 1 + n);
	}
	printf("%lld\n", ans);
}

int main() {
	rd(T); while(T--) solve();
	return 0;
}
posted @ 2025-09-29 11:00  Sktn0089  阅读(19)  评论(0)    收藏  举报