很套路地把线段拆为左端点为+1,右端点为-1的两个点后,按照位置从小到大扫过去,当某点为右端点时,统计当前集合中线段个数,然后累加C(sum,k)。(因为左右端点赋了权值,所以集合中线段个数即为当前权值和)
这样做后发现是会有重复的,样例1就很良心地提醒了这一点。
考虑如何容斥,发现不会…
所以改变一下组合数的含义,每次统计时,我们强制当前的最后一条线段必选选,那么现在,就需要在另外的sum-1条线段中选取k-1条了。累加C(sum-1,k-1),不需要去重。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=3e5+5,MOD=998244353;
int n,k,x,y,tot,ans,sum;
int bin[N],inv[N];
struct number{int x,w;}num[N<<1];
inline int C(int n,int m)
{
if (n<m) return 0ll;
if (!m || n==m) return 1l;;
return bin[n]*inv[n-m]%MOD*inv[m]%MOD;
}
inline int pow(int a,int n)
{
int res=1ll;
while (n)
{
if (n&1ll) res=res*a%MOD;
a=a*a%MOD;
n>>=1ll;
}
return res;
}
inline bool cmp(number a,number b)
{
return a.x<b.x || a.x==b.x && a.w>b.w;
}
signed main(){
scanf("%lld%lld",&n,&k);
bin[0]=1; inv[0]=1;
for (register int i=1; i<=n; ++i) bin[i]=bin[i-1]*i%MOD;
for (register int i=1; i<=n; ++i) inv[i]=pow(bin[i],MOD-2ll)%MOD;
for (register int i=1; i<=n; ++i)
{
scanf("%lld%lld",&x,&y);
num[++tot]=(number){x,1};
num[++tot]=(number){y,-1};
}
sort(num+1,num+tot+1,cmp);
for (register int i=1; i<=tot; ++i)
{
if (num[i].w==-1) ans=(ans+C(sum-1,k-1))%MOD;
sum+=num[i].w;
}
printf("%lld\n",ans);
return 0;
}