codeforces-#672-D

codeforces-#672-D

D. Rescue Nibel!

题意

给出n<1e5个区间[Li,Ri] ,(Li,Ri<1e9)

要求找到k个区间他们有公共点

问有多少组区间 (每组k个)满足要求

题解

有关区间统计问题 想到差分前缀 按端点排序 和离散化

我们定义P(x)为覆盖x点的区间有多少个

定义S(x)为以x为起点的区间有多少个

由于区间端点值的范围较大而区间个数很小 可以离散化左右端点

然后对于每个区间的端点值Li处 Psum[Li]++ , Ri处Psum[Ri+1]–;

对Psum求前缀和 那么对于Psum[i] 就相当于覆盖i点的区间有多少个

对于S(x)可以在离散化后直接统计记为Cnt[i]

那么以一个点x作为起始点 求有多少组区间可以满足他们的公共点包括x

那么对于这个点对答案产生的贡献=C(Psum[x],k)-C(Psum[x]-Cnt[x],k)

减去C(Psum[x]-Cnt[x],k)是因为

统计的标准是以x作为起始点有多少组区间可以满足他们的公共点包括x

那么Psum[x]-Cnt[x]个区间虽然在x处有公共点但是不以x为起始点

它们会在以y,(y<x)为起始点时被统计入答案 所以要减去

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
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define endl '\n'
#define Turnoff std::ios::sync_with_stdio(false)
const ll Max=6e5+5;
const int Mod=998244353;

ll fac[Max],inv[Max];
int Psum[Max],Cnt[Max];
struct Seg{int L,R;}seg[Max];
ll qpow(ll x,ll y){
ll ans=1;
while(y){
if(y&1)ans=ans*x%Mod;
x=x*x%Mod;y>>=1;
}
return ans;
}
void init(){
fac[0]=1;
for(int i=1;i<=Max;i++)fac[i]=fac[i-1]*i%Mod;
inv[Max]=qpow(fac[Max],Mod-2);
for(int i=Max-1;i>=0;i--)inv[i]=inv[i+1]*(i+1)%Mod;
}
ll C(int n,int m){return n>=m?fac[n]*inv[m]%Mod*inv[n-m]%Mod:0;}
vector<int>data;
int main() {
Turnoff;
ll ans=0;init();
///cout<<C(3,1)<<" "<<C(1,3)<<endl;
int n,k;cin>>n>>k;
for(int i=0;i<n;i++){
int L,R;cin>>L>>R;
seg[i]={L,R};
data.push_back(L);
data.push_back(R);
}
sort(data.begin(),data.end());
data.erase(unique(data.begin(),data.end()),data.end());
for(int i=0;i<n;i++){
seg[i].L=lower_bound(data.begin(),data.end(),seg[i].L)-data.begin();
seg[i].R=lower_bound(data.begin(),data.end(),seg[i].R)-data.begin();
Cnt[seg[i].L]++;Psum[seg[i].L]++,Psum[seg[i].R+1]--;
}
int len=data.size();
for(int i=1;i<len;i++)Psum[i]+=Psum[i-1];
for(int i=0;i<len;i++){
ans=(Mod+ans+C(Psum[i],k)-C(Psum[i]-Cnt[i],k))%Mod;
}
cout<<ans<<endl;
}