Codeforces Round #672 (Div. 2) D. Rescue Nibel! (差分 + 组合数)

链接: D. Rescue Nibel!

题意:
有 n 栈灯 ,每栈灯在 [ l , r] 时间段内是开着的 ,现在需要选择 k 栈灯 ,使他们能在同一时间内打开 ,问有多少种选择方法 。
思路:

  1. 如果不考虑重复的情况 , 我们可以算出每个时间点 有多少盏灯亮着 ,然后用一个组合数就可以把答案算出来 ,但这样明显会有很多重复的情况 。 再考虑每栈灯都有一个唯一的起点,可以用起点代表每栈灯 ,对于每个时间点 , 我们只计算开始时间在这个点的灯产生的贡献 ,也就是在这选择的灯必须包含这几栈开始时间在这个点的灯 ,即贡献为 (总的灯里选 k 个) - (起点不在这个点的灯里选 k 个) 。
  2. 我们可以先离散化一下,再用差分数组 统计每个时间点亮着的灯的数量 。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+7;
const int mod = 998244353;
ll  a1[maxn],b1[maxn];
struct node{
    
    
    ll l,r;
}num[maxn];
ll n,k,val[maxn],cnt;
ll ans , d[maxn] , x[maxn] , c[maxn];
ll quickpow(ll a ,ll b){
    
    
   ll ans=1;
   while(b>0){
    
    
         if(b&1) ans=ans*a%mod;
         a=a*a%mod;
         b>>=1;
   }
   return ans;
}
ll ni(ll x){
    
    
    return quickpow(x,mod-2);
}
void init (){
    
    
     a1[0]=1;
     for(int i = 1 ;i < maxn ;i ++){
    
    
        a1[i] = (a1[i-1] * i) % mod;
     }
     b1[maxn - 1] = ni(a1[maxn - 1]);
     for(int i = maxn - 2 ;i >= 0 ;i --){
    
    
         b1[i] = b1[i+1] * (i + 1) % mod;
     }
}
ll C(ll n,ll m){
    
    
    if(n < m) return 0;
    return (a1[n] * b1[m] % mod) * b1[n-m] % mod;
}
int main() {
    
    
   scanf("%lld%lld",&n,&k);
   init();
   for(int i = 1; i <= n; i ++){
    
    
       scanf("%lld%lld",&num[i].l,&num[i].r);
       val[cnt ++] = num[i].l;
       val[cnt ++] = num[i].r;
   }
   sort(val,val + cnt);
   cnt = unique(val,val + cnt) - val;
   for(int i = 1; i <= n; i ++){
    
    
       num[i].l = lower_bound(val , val + cnt , num[i].l) - val + 1;
       num[i].r = lower_bound(val , val + cnt , num[i].r) - val + 1;
       //printf ("%lld %lld %lld\n",num[i].l,num[i].r,cnt);
   }
   for(int i = 1; i <= n; i ++){
    
    
       x[num[i].l] ++;
       d[num[i].l] ++;
       d[num[i].r + 1] -- ;
   }
   for(int i = 1; i <= cnt; i ++){
    
    
       c[i] = c[i - 1] + d[i];
   }
   for(int i = 1; i <= cnt; i ++){
    
    
       if(c[i] < k) continue;
       //printf ("%lld %lld ",C(c[i] , k),C(c[i] - x[i] , k));
       ans = (ans + C(c[i] , k) - C(c[i] - x[i] , k)  + mod) % mod;
   }
   printf ("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/hddddh/article/details/108791379