Rescheduling the Exam

Rescheduling the Exam

Created by LXC on Sun Apr 7 11:39:21 2024

https://codeforces.com/problemset/problem/1650/E

ranting: 1900

tag: binary search, data structures, greedy, implementation, math, sortings

problem

小 P 有 $n$ 场考试要考,它们的开始时间是 $a_1\sim a_n$(保证 $a$ 按升序排列),所有的考试都会在 $d$ 之前结束。

对于时间相邻的两场考试 $a_{i-1},a_{i}$,定义它们的距离为 $a_{i}-a_{i-1}-1$,而 $a_1$ 与 $a_{0}$ 的距离定义为 $a_1$ 与 $0$ 的距离。

定义对于这个数组 $a$ 的 $\mu$ 值为所有 $a_{i-1}$ 与 $a_{i}$ 之间距离的最小值。

你可以改变某一个 $a_i$ 的值(但不能 $>d$),最大化修改后 $a$ 的 $\mu$ 的值,输出最大的 $\mu$ 值。

翻译提供者:@DaiRuiChen007

solution

考虑当前最小间距的个数,

如果超过2,那么移动一个位置,仍然存在最小间距,因此答案就是最小间距。

如果为2,那么只有三个相邻的数产生相邻的两个最小间距,在将中间的数移动的情况下,才有可能让最小间距变大。

如果为1,那么形成最小间距的两个数都有可能移动使得最小间距变大,取最大值。

如何移动,我们将移动一个数,将减少1~2个间距,增加0~1个间距(取决于移除的数是不是最后一个数),然后将这个数移动到最后一个位置d或者最大间距的中间,这两种情况形成的最小间距需要取最大值。

code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102

#include <bits/stdc++.h>
// #define SINGLE_INPUT
#define ll long long
#define ull unsigned long long
#define N 500005
#define MOD 998244353
using namespace std;

random_device seed;
ranlux48 engine(seed());
int random(int l, int r) {
uniform_int_distribution<> distrib(l, r);
return distrib(engine);
}
template<class t,class u> ostream& operator<<(ostream& os,const pair<t,u>& p) {
return os<<'['<<p.first<<", "<<p.second<<']';
}
template<class t> ostream& operator<<(ostream& os,const vector<t>& v) {
os<<'['; int s = 1;
for(auto e:v) { if (s) s = 0; else os << ", "; os << e; }
return os<<']';
}
template<class t,class u> ostream& operator<<(ostream& os,const map<t,u>& mp){
os<<'{'; int s = 1;
for(auto [x,y]:mp) { if (s) s = 0; else os << ", "; os<<x<<": "<<y; }
return os<<'}';
}

void sol() {
ll n, d;
cin >> n >> d;
vector<ll> a(n+1);
for (int i=1; i<=n; i++) {
cin >> a[i];
}
auto opt = [&](map<ll,ll> itv, ll l, ll m, ll r=-1)->ll {
// cout << "opt " << l << " " << m << " " << r << endl;
if (--itv[m-l-1] == 0) itv.erase(m-l-1);
if (a[n] != m) {
if (--itv[r-m-1] == 0) itv.erase(r-m-1);
itv[r-l-1]++;
}
// cout << itv << endl;
// 放最后
ll t = min(d-(m == a[n]?a[n-1]:a[n])-1, itv.begin()->first);
// cout << "set last : " << t << endl;
// 放最大间隔中间
int mx = itv.rbegin()->first;
if (--itv[mx] == 0) {
itv.erase(mx);
}
itv[(mx+1)/2-1]++;
itv[mx-(mx+1)/2]++;
return max(itv.begin()->first, t);
};
map<ll,ll> itv;
for (int i=1; i<=n; i++) {
itv[a[i]-a[i-1]-1]++;
}
auto [mn, cnt] = *itv.begin();
// cout << mn << " -- " << cnt << endl;
if (cnt > 2) {
cout << mn << "\n";
} else if (cnt == 2) {
for (int i=1; i<n; i++) {
if (a[i] - a[i-1] - 1 == mn && a[i+1] - a[i] - 1 == mn) {
cout << opt(itv, a[i-1], a[i], a[i+1]) << "\n";
return ;
}
}
cout << mn << "\n";
} else {
if (a[1]-a[0]-1 == mn) cout << opt(itv, a[0], a[1], a[2]) << "\n";
else if (a[n]-a[n-1]-1 == mn) cout << max(opt(itv, a[n-2], a[n-1], a[n]), opt(itv, a[n-1], a[n])) << "\n";
else
for (int i=2; i<n; i++) {
if (a[i] - a[i-1] - 1 == mn) {
cout << max(opt(itv, a[i-2], a[i-1], a[i]), opt(itv, a[i-1], a[i], a[i+1])) << "\n";
return ;
}
}
}
}

int main() {
cout << setprecision(15) << fixed;
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
#ifndef SINGLE_INPUT
int t;
cin >> t;
while (t--) {
sol();
}
#else
sol();
#endif
return 0;
}