HPU personal training
K - Two Contests
原题链接:https://agc040.contest.atcoder.jp/tasks/agc040_b?lang=en
题目大意:
给一个区间集合,将这些区间分为两个集合,求两个区间中线段交集的最大值。
解题思路:
首先找到这些区间的右端点在最左端的区间p,左端点在最右端的区间q。
- 如果p,q在同一个集合中,那么这个集合的最大交集就是p_r - q_l,而另一个只放一个最大的区间,得到ans1。
- 如果不在同一个区间,想一下集合区间的特征,含有p的集合S中,区间的右端点都大于p的右端点,那么他们的最大交集就是p_R - min_L{ L属于集合S} + 1,含有q的集合T中,区间的左端点都小于q的左端点,那么他们的最大交集就是min_R{R属于集合T} - q_l + 1.可以知道如果直接从所有集合中找最合适期间,那么找到的这个区间可能既在S集合中又在T集合中,所以不能这样找。因此要用到后缀最小值。首先对于每一个区间存储R-mxl+1和mnR-L+1两个数据。然后按其中一个数据对数组排列大小,(要从大的开始,因为大的在一个集合中,所有比他小的都在另一个集合中,然后从大到小找两个集合中的最小交集,这样就可以用后缀最小值了。)
代码:
1 #include <bits/stdc++.h>
2 using namespace std;
3 const int N = 1e5 + 7;
4 struct aa{
5 int first,second;
6 }P;
7 aa arr[N];//记录区间
8 int minnore[N];
9 aa S[N];
10
11 bool cmp1(aa a, aa b){
12 return a.first > b.first;
13 }
14
15 int main(){
16 int q, L, R, mxL = 0, mnR = 1e9 + 7, RR, LL;
17 int flag1 = 0, flag2 = 0, maxlen = 0;
18 scanf("%d", &q);
19 for(int i = 0; i < q; i ++ ){
20 scanf("%d%d", &L, &R);
21 arr[i].first = L;
22 arr[i].second = R;
23 if(L > mxL){
24 mxL = L;
25 RR = R;
26 flag1 = i;
27 }
28 if(R < mnR){
29 mnR = R;
30 LL = L;
31 flag2 = i;
32 }
33 maxlen = max(maxlen, R - L + 1);
34 }
35 int ans1 = maxlen;
36 if(mnR >= mxL) ans1 += mnR - mxL + 1;
37 if(flag1 == flag2){
38 cout << ans1 << endl;
39 return 0;
40 }
41 for(int i = 0; i < q; i ++ ){
42 S[i].first = max(arr[i].second - mxL + 1, 0);
43 S[i].second = max(mnR - arr[i].first + 1, 0);
44 }
45 sort(S, S + q, cmp1);
46 minnore[q-1] = S[q - 1].second;
47 for(int i = q - 2; i >= 0; i --){
48 minnore[i] = min(minnore[i + 1], S[i].second);
49 }
50 int ans2 = 0;
51 for(int i = 0; i < q; i ++ ){
52 ans2 = max(ans2, S[i].first + minnore[i+1]);
53 }
54 cout << max(ans2,ans1) <<endl;
55 return 0;
56 }