[JOI 2024 Final] 室溫

maniubi發表於2024-10-06

[JOI 2024 Final] 室溫

題意

給出一個長度為 \(n\) 的序列 \(a\),給出數 \(T\)

可以進行若干次操作,每次操作可以任選數 \(a_i\),將 \(a_i \leftarrow a_i - T\)

可以選定一個數 \(t\),使得操作完成後 \(\max |a_i-t|\) 最小 。

思路

首先進行操作等價於將 \(a_i \leftarrow a_i \bmod T\)

然後考慮對於固定的序列 \(a\),如何選定 \(t\) 使答案最小。

\(t = \frac{\min a_i + \max a_i}{2}\) 時,總答案最小。

因為當選定的 \(t = \min a_i\)\(\max a_i\) 時,答案為 \(\max a_i - \min a_i\)

\(t\) 往中間走的時候,答案會變小,最小時就是 \(t\) 取到中點時,答案為極差的一半。

如果除不盡怎麼辦呢?是向上取整還是向下取整?

應該是向上取整,因為除不盡時 \(t\) 一定往左或往右偏一點,較長的為答案,就是向上取整。

現在問題就變為了求出序列最小的極差,除以二向下取整就是答案。

首先想到將 \(a_i \bmod T\) 後排序,\(a_n-a_1\) 就是最小極差,但發現樣例都不過。

發現問題:我可以將 \(a_1\)\(a_i\) 的數少減一個 \(T\),變為 \(a_1+T\)\(a_i+T\)

這樣新的極差就變為了 \(a_i+T-a_{i+1}\),列舉每個 \(i\) 取最小值即可。

注意原始的極差也要統計入答案。

程式碼

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 5e5 + 5;
int ans = 1e18, n, t, a[N];
signed main() {
	cin >> n >> t;
	for (int i = 1; i <= n; i ++)
		cin >> a[i], a[i] %= t; 
	sort(a + 1, a + n + 1);
	ans = (a[n] - a[1] + 1) / 2;
	for (int i = 1; i < n; i ++) 
		ans = min(ans, (a[i] + t - a[i + 1] + 1) / 2);
	cout << ans;
	return 0;
}

相關文章