首页 > 其他分享 >[ICPC2022济南站] H.Set of Intervals 【分类讨论】

[ICPC2022济南站] H.Set of Intervals 【分类讨论】

时间:2022-11-28 20:24:03浏览次数:43  
标签:ICPC2022 Set r1 int Intervals l2 端点 l1 区间

分析:

只有一个区间的时候输出1

只有两个区间的时候,只有三种情况:包含,相离,相交。可以推出一个数学式子计算相交和相离的情况下的答案,我们用$getans(l_1,r_1,l_2,r_2)$表示。那么包含的情况的答案则可以通过容斥原理,假设$[l_1,r_1]$是小的区间,则$getans(l_1,r_1,l_2,r_2)+getans(l_2,r_2,l_1,r_1)-getans(l1,r1,l1,r1)$得到。

接下来我们考虑其他情况:

假设现在对于所有区间,其最小的左端点位置为$minl$,由第一个区间提供,最大的右端点位置为$maxr$,也由第一个区间提供,那么对于剩下的其他$n-1$个区间,可以计算他们的最小值$secl$和他们的最大值$secr$,答案就是上面两个区间包含的情况的答案。

如果$minl$和$maxr$由不同的区间提供,也就是分别由第一个和第二个区间提供。那么还是同样求出其他$n-2$个区间的$secl$和$secr$。

接下来,分几种情况讨论:

1.两个端点一个在$[minl,maxr]$之中,另一个在$[secl,secr]$之中,这种情况完全可以取到,利用计算包含的函数计算。

2.两个端点都在$[minl,secl-1]$之中,这个情况可以发现,左端点一定是由第一个区间和其他某个区间的并构成,因此能取到$[minl,secl-1]$的全集。而右端点只能由第二个区间获得,因为其他区间染指不到$secl-1$以及之前。所以可以利用相交或者包含的那个函数计算

3.两个端点都在$[secr+1,maxr]$之中,这个情况和情况2对称

4.左端点在$[minl,sec-1]$,右端点在$[secr+1,maxr]$。这时候,如果有$n\ge 4$,那么总是可以把第一个区间和其他区间合并,第二个区间和其他区间合并,于是左右端点能取到所有情况,利用相离的计算即可。否则$n=3$,此时可以选择将左端点和其他区间合并,再将右端点和其他区间合并,分别计算结果,然后再减去算重的部分。

代码:

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn = 105000;
 5 
 6 struct node{
 7     int l,r;
 8 }p[maxn];
 9 
10 long long calc(int l1,int r1,int l2,int r2){
11     if(l1 > r1) return 0;
12     if(l2 > r2) return 0;
13     if(r1 < l2){
14     return 1ll*(r1-l1+1)*(r2-l2+1);
15     }else{
16     r1 = min(r1,r2);
17     l2 = max(l2,l1);
18     if(l1 > r1) return 0;
19     if(l2 > r2) return 0;
20     return 1ll*(l2-l1)*(r2-l2+1)+1ll*(r1-l2+1)*(r2-l2+r2-r1)/2;
21     }
22 }
23 
24 int main(){
25     ios::sync_with_stdio(false);
26     int t; cin >> t;
27     while(t--){
28     int n;
29     cin >> n;
30     for(int i=1;i<=n;i++) cin >> p[i].l >> p[i].r;
31     if(n == 1){cout<<1<<endl;continue;}
32     int samepos = 0;
33     int minnl = 1e9,ps1 = 0,maxxr = -1e9,ps2 = 0;
34     for(int i=1;i<=n;i++){
35         if(p[i].l < minnl && p[i].r > maxxr){
36         ps1 = i,minnl = p[i].l;
37         ps2 = i,maxxr = p[i].r;
38         }else{
39         if(p[i].l < minnl){
40             ps1 = i;
41             minnl = p[i].l;
42         }else if(p[i].r > maxxr){
43             ps2 = i;
44             maxxr = p[i].r;
45         }
46         }
47     }
48     if(ps1 == ps2){
49         samepos = 1;
50         swap(p[1],p[ps1]);
51     }else{
52         if(ps2 == 1 && ps1 == 2){
53         swap(p[1],p[2]);
54         }else if(ps2 == 1){
55         swap(p[1],p[2]);
56         swap(p[ps1],p[1]);
57         }else{
58         swap(p[1],p[ps1]);
59         swap(p[2],p[ps2]);
60         }
61     }
62     if(n == 2 && !samepos){
63         cout<<calc(p[1].l,p[1].r,p[2].l,p[2].r)<<endl;
64         continue;
65     }
66     int secl = 1e9,secr = -1e9;
67     int st = (samepos == 1?2:3);
68     for(int i=st;i<=n;i++){
69         secl = min(secl,p[i].l);
70         secr = max(secr,p[i].r);
71     }
72     long long p1 = calc(minnl,maxxr,secl,secr)+calc(secl,secr,minnl,maxxr)-calc(secl,secr,secl,secr);
73     if(samepos == 1){
74         cout<<p1<<endl;
75     }else{
76         //both l,secl-1
77         p1 += calc(minnl,secl-1,p[2].l,secl-1);
78         //both r,secr-1
79         p1 += calc(secr+1,p[1].r,secr+1,maxxr);
80         //l,secl-1;r,secr-1;
81         if(n >= 4){
82         p1 += calc(minnl,secl-1,secr+1,maxxr);
83         }else{
84         if(p[1].r >= secl-1 || p[2].l <= secr+1){
85 
86             p1 += calc(minnl,secl-1,secr+1,maxxr);
87         }else{
88             p1 += calc(minnl,secl-1,p[2].l,maxxr)+calc(minnl,p[1].r,secr+1,maxxr)-calc(minnl,p[1].r,p[2].l,maxxr);
89         }
90         }
91         cout<<p1<<endl;
92     }
93     }
94 }

 

 

 

 

标签:ICPC2022,Set,r1,int,Intervals,l2,端点,l1,区间
From: https://www.cnblogs.com/Menhera/p/16933478.html

相关文章