0%

1750.救生员

1750. 救生员

题目描述:

农夫约翰为他的牛开设了一个游泳池,他认为这将帮助它们放松并产出更多的奶。

为了确保安全,他雇佣了 $ N $ 头奶牛作为救生员,每头奶牛的工作班次都是一段连续的时间。

为了简单起见,游泳池每天的开放时间从时刻 $ 0 $ 到时刻 $ 1000 $ 。

每个奶牛的工作班次都可以用两个整数来描述,它们分别表示该奶牛工作班次的开始时刻和结束时刻。

例如,从时刻 $ t = 4 $ 开始工作并在时刻 $ t=7 $ 结束工作的救生员,它的工作时间为三个时间单位(请注意,时间“段”两端的端点是时间轴上的“点”)。

不幸的是,由于资金紧张问题,约翰不得不解雇一头奶牛。

请问通过合理裁员,剩余救生员的工作班次仍然可以覆盖的最大时间有多长?

一个时间间隔内如果存在至少一名救生员当值,那么这个时间间隔就认为是被覆盖的。

输入格式

第一行包含整数 $ N $ 。

接下来 $ N $ 行,每行描述一个救生员的工作班次,包含两个整数,表示一个救生员的开始工作时刻和结束工作时刻。

所有时刻各不相同,不同救生员的工作班次可能有覆盖。

输出格式

输出一个整数,表示解雇掉一头奶牛后,剩余救生员的工作班次仍然可以覆盖的最长时间。

数据范围

$ 1 \le N \le 100 $

输入样例:

1
2
3
4
3
5 9
1 4
3 7

输出样例:

1
7

题解:

由于数据范围比较小,所以方法比较多。

  • 直接使用区间加,每次枚举删除的区间,求出删除之后得到的区间。
  • 使用区间合并。区间合并,维护一个区间,遇到一个新区间时进行比较,如果新区间的起点小于所维护区间的终点,更新维护区间的终点为二者终点的最大值(包含了两个区间相交,和相容)。 如果新区间的起点大于所维护区间的终点,那么更新所维护区间的起点和终点为新区间(相离)。
  • 使用区间加,把每一段都加上,那么最后得到的数组中。如果元素等于 $ 1 $ ,说明只被一个区间覆盖,使用一个新的前缀和数组统计 $ 1 $ 的个数。这样的话可以很方便的计算出每一个区间中唯一覆盖的长度。这样的话就可以得到删除一个区间后,剩余了多少长度。

代码:

方法二

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
using namespace std;
using namespace FAST_IO;
const ll mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const ll INF_LL = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-5;
const int maxn = 1e3 + 10;
const int maxm = 1e5 + 10;
int t, n, m, k;
vector<PII> a;
int main()
{
// #define COMP_DATA
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n;
for (int i = 1, x, y; i <= n; i++)
{
cin >> x >> y;
a.push_back({x, y});
}
sort(a.begin(), a.end());
// 每次枚举删除的 i
int ans = 0;
for (int i = 0; i < a.size(); i++)
{
int sum = 0, st = -1, ed = -1;
for (int j = 0; j < a.size(); j++)
{
if (j != i)
{
if (ed >= a[j].first)
{
ed = max(ed, a[j].second);
}
else
{
sum += ed - st;
st = a[j].first;
ed = a[j].second;
}
}
}
sum += ed - st;
ans = max(ans, sum);
}
cout << ans << endl;
return 0;
}

方法三

注意这里是区间长度,化为点的话就是前闭后开,这样的话区间加就不需要 a[r + 1]-- 而是变成了 a[r]--.

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
using namespace std;
using namespace FAST_IO;
const ll mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const ll INF_LL = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-5;
const int maxn = 1e3 + 10;
const int maxm = 1e5 + 10;
int t, n, m, k;
int a[maxn];
int b[maxn];
vector<PII> c;
int main()
{
// #define COMP_DATA
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n;
for (int i = 1, x, y; i <= n; i++)
{
cin >> x >> y;
c.push_back({x, y});
a[x]++;
a[y]--;
}
int sum = 0;
if (a[0])
sum = 1;
if (a[0] == 1)
b[0] = 1;
for (int i = 1; i <= 1001; i++)
{
a[i] += a[i - 1];
if (a[i])
sum++;
if (a[i] == 1)
b[i] = 1;
b[i] += b[i - 1];
}
int ans = INF;
for (int i = 0; i < c.size(); i++)
{
if (c[i].first == 0)
{
ans = min(ans, b[c[i].second - 1]);
}
else
{
ans = min(ans, b[c[i].second-1] - b[c[i].first - 1]);
}
}
cout << sum - ans << endl;
return 0;
}