CF1420D Rescue Nibel (贪心+思维)

22 篇文章 0 订阅
22 篇文章 0 订阅

链接

题意:

n n n 条线段 [ l i , r i ] [l_i,r_i] [li,ri],你需要从中选出 k k k 条令他们的交集不为空,求方案数对 998244353 998244353 998244353 取模的结果。

分析:

看完题我们还知道求交集,那么求交集一定是 m a x ( l i , l j ) < = m i n ( r i , r j ) max(l_i,l_j)<=min(r_i,r_j) max(li,lj)<=min(ri,rj)这样交集才不为空,所以我们可以先按左节点排序,右节点排序,排序完我们知道左节点一定会单增的。我们知道左节点是单增的之后我们其实已经比较完 m a x ( l i , l j ) max(l_i,l_j) max(li,lj)了,当着这个节点的左节点一定最大。(因为我们排序了。)

然后我们只需要看有多少 r j r_j rj(前(i-1)个中)大于等于l_i,这就需要我们维护一个树状数组了,没遍历一个就将一个 r j r_j rj放入树状数组中。


/// 欲戴皇冠,必承其重。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pii;
typedef unsigned long long ull;

#define x first
#define y second
#define PI acos(-1)
#define inf 0x3f3f3f3f
#define lowbit(x) ((-x)&x)
#define debug(x) cout << #x << ": " << x << endl;

const int MOD = 998244353;
const int mod = 998244353;
const int N = 6e5 + 10;
const int dx[] = {0, 1, -1, 0, 0, 0, 0};
const int dy[] = {0, 0, 0, 1, -1, 0, 0};
const int dz[] = {0, 0, 0, 0, 0, 1, -1};
int day[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

ll n, m;
ll fac[N],infac[N];
struct node 
{
    ll l,r;
}q[N];
bool cmp(node a,node b){
    if(a.l!=b.l)
    return a.l<b.l;
    return a.r<b.r;
}
ll qpow(ll a, ll b){
    ll ans=1;
    while(b){
        if(b&1) ans=ans*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return ans;
}
ll a[N],b[N];
ll num;
void add(ll x){
    while(x<=num){
        b[x]++;
        x+=lowbit(x);        
    }    
}
ll ask(ll x){
    ll ans=0;
    while(x){
        ans+=b[x];
        x-=lowbit(x);
    }
    return ans;
}
ll C(ll x,ll y){
    return fac[x]*infac[y]%mod*infac[x-y]%mod;
}
void solve(){    
    scanf("%lld%lld",&n,&m);
    ll ans=0;
    fac[0]=infac[0]=1;
    for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mod;
    for(int i=1;i<=n;i++) infac[i]=qpow(fac[i],mod-2);
    for(int i =1;i<=n;i++){
        scanf("%lld%lld",&q[i].l,&q[i].r);
        a[++num]=q[i].l;
        a[++num]=q[i].r;
    }
    sort(q+1,q+1+n,cmp);
    sort(a+1,a+1+num);
    num=unique(a+1,a+1+num)-a-1;
    for(int i=1;i<=n;i++){
        q[i].l=lower_bound(a+1,a+1+num,q[i].l)-a;
        q[i].r=lower_bound(a+1,a+1+num,q[i].r)-a;
        ll cnt = ask(num)-ask(q[i].l-1);//ll cnt = (i-1)-ask(q[i].l-1);
        add(q[i].r);
        if(cnt>=m-1){
            ans=(ans+C(cnt,m-1))%mod;
        }        
    }
    printf("%lld\n",ans);
}
int main()
{
    ll t = 1;
    //scanf("%lld", &t);
    while(t--)
    {
        solve();
    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值