D. Rescue Nibel!
题意:总共有n个线段,问选择k条线段,使得他们相交于一点的方案数。
思路:用类似差分的思想,将每条线段的l和r+1放进数组里并且分别带有1和-1的权值,将数组按照坐标大小排序,如果坐标大小不同按照权制大小排序,权值小的放在前面,然后依次遍历下来,把方案定义为以第i个灯泡为末尾(即该灯泡的坐标在选的坐标里最大)的方案数,这些方案是不重不漏的,加起来就是答案了,然后模数不是质数,要用扩展欧几里得求,然后我忘了咋写了。
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
struct node{
ll x;
int d;
bool operator <(const node&W)const
{
if(x==W.x)
return d<W.d;
return x<W.x;
}
};
const int N=600010;
const int mod= 998244353;
node q[N];
int cnt;
ll fact[N];
ll infact[N];
ll qmi(ll a,int b)
{
ll res=1;
while(b)
{
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res%mod;
}
ll exgcd(ll a,ll b,ll &x,ll & y);
void init()
{
fact[0]=infact[0]=1;
for(int i=1;i<N;i++)
{
fact[i]=fact[i-1]*i%mod;
ll x, y;
ll d=exgcd(fact[i],mod,x,y);
infact[i]=(x%mod+mod)%mod;
}
}
ll C(ll a,ll b)
{
if(b>a) return 0;
return fact[a]*infact[a-b]%mod*infact[b]%mod;
}
ll exgcd(ll a,ll b,ll &x,ll & y)
{
if(!b)
{
x=1,y=0;
return a;
}
ll d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
int main()
{
int n,m;
init();
// cout<<fact[3]<<' '<<C(6,3)<<endl;
cin>>n>>m;
for(int i=0;i<n;i++)
{
int l,r;
cin>>l>>r;
q[cnt++]={
l,1};
q[cnt++]={
r+1,-1};
}
sort(q,q+cnt);
int ct=0;
ll res=0;
for(int i=0;i<cnt;i++)
{
//cout<<ct<<endl;
if(q[i].d==1)
res = (res+C(ct,m-1))%mod;
ct+=q[i].d;
}
cout << res << endl;
return 0;
}