Codeforces Round #672 (Div. 2) D. Rescue Nibel!

D. Rescue Nibel!
Description

Ori and Sein have overcome many difficult challenges. They finally lit the Shrouded Lantern and found Gumon Seal, the key to the Forlorn Ruins. When they tried to open the door to the ruins… nothing happened.

Ori was very surprised, but Sein gave the explanation quickly: clever Gumon decided to make an additional defence for the door.

There are n lamps with Spirit Tree’s light. Sein knows the time of turning on and off for the i-th lamp — li and ri respectively. To open the door you have to choose k lamps in such a way that there will be a moment of time when they all will be turned on.

While Sein decides which of the k lamps to pick, Ori is interested: how many ways there are to pick such k lamps that the door will open? It may happen that Sein may be wrong and there are no such k lamps. The answer might be large, so print it modulo 998244353.

Input

First line contains two integers n and k (1≤n≤3⋅105, 1≤k≤n) — total number of lamps and the number of lamps that must be turned on simultaneously.

Next n lines contain two integers li ans ri (1≤li≤ri≤109) — period of time when i-th lamp is turned on.

Output

Print one integer — the answer to the task modulo 998244353.

Examples
input
7 3
1 7
3 8
4 5
6 7
1 3
5 10
8 9
output
9
input
3 1
1 1
2 2
3 3
output
3
input
3 2
1 1
2 2
3 3
output
0
input
3 3
1 3
2 3
3 3
output
1
input
5 2
1 3
2 4
3 5
4 6
5 7
output
7
Note

In first test case there are nine sets of k lamps: (1,2,3), (1,2,4), (1,2,5), (1,2,6), (1,3,6), (1,4,6), (2,3,6), (2,4,6), (2,6,7).

In second test case k=1, so the answer is 3.

In third test case there are no such pairs of lamps.

In forth test case all lamps are turned on in a time 3, so the answer is 1.

In fifth test case there are seven sets of k lamps: (1,2), (1,3), (2,3), (2,4), (3,4), (3,5), (4,5).

题意: 给出n盏灯,从这n盏灯里面选出k盏,且这k盏此时被选出来必须是正在亮的,下面n行输入每盏灯的亮的时间段,问:有多少种选法。

题解: 先离散化,差分,算出每个点覆盖的区间数量s[i] ,
(s[左端点]++,s[右端点+1]- -)然后对s求前缀和)

并记录这个点含的左端点数量bb[i]。对于每一个点,求组合数的时候,每个方案必须包含至少一个左端点,这样就不会重复。即 C ( s u m [ i ] , k ) − C ( s u m [ i ] − b b [ i ] , k ) C ( s u m [ i ] , k ) − C ( s u m [ i ] − b b [ i ] , k ) C(sum[i],k)C(sum[i]bb[i],k)
(i 全部点的数量任取k个,减掉全部都不取左端点的数量)

组合数可以用定义求解。 c a b = a ! b ! ∗ ( a − b ) ! c_a^b=\frac{a!}{b!*(a-b)!} cab=b!(ab)!a!

求分母的时候要用逆元

c++ AC 代码

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10, mod = 998244353;
typedef long long ll;
ll n, m, sum[N], bb[N];
ll in[N], inv[N]; // in表示阶乘,inv表示逆元
vector<int> alls;

struct node
{
	int l;
	int r;
} a[N];
ll qp(ll a, ll b) // 快速幂算法
{
	ll res = 1;
	while (b)
	{
		if (b & 1)
			res = res * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return res % mod;
}
int find(int x)
{
	return lower_bound(alls.begin(), alls.end(), x) - alls.begin();
	// 找到离散化对应的下标
}

void ini() // 初始化阶乘数组以及逆元数组
{
	in[0] = inv[0] = 1;
	for (int i = 1; i < N; i++)
		in[i] = in[i - 1] * i % mod;
	inv[N - 1] = qp(in[N - 1], mod - 2);
	for (int i = N - 2; i >= 1; i--)
		inv[i] = inv[i + 1] * (i + 1) % mod;
}

ll c(ll a, ll b) // 求组合数函数
{
	if (a < b)
		return 0;
	return (in[a] * inv[b]) % mod * inv[a - b] % mod;
}

int main()
{
	scanf("%lld%lld", &n, &m);
	ini();
	for (int i = 0; i < n; i++)
	{
		scanf("%d%d", &a[i].l, &a[i].r);
		alls.push_back(a[i].l);
		alls.push_back(a[i].r + 1);
	}
	sort(alls.begin(), alls.end());
	alls.erase(unique(alls.begin(), alls.end()), alls.end());	// 去重
	for (int i = 0; i < n; i++)
	{
		int x = find(a[i].l), y = find(a[i].r + 1);
		bb[x]++;
		sum[x]++, sum[y]--;
	}
	for (int i = 1; i < alls.size(); i++)
		sum[i] += sum[i - 1];	// 每个端点覆盖数
	ll ans = 0;
	for (int i = 0; i < alls.size(); i++)
	{
		if (sum[i] < m)
			continue;
		ans = (ans + c(sum[i], m) - c(sum[i] - bb[i], m) + mod) % mod;
		//对于某一个点,必须选到左端点是这个点的组合数(每个组合数里面取,至少有一个是左端点)
	}
	printf("%lld\n", ans);
	// system("pause");
	return 0;
}

转载自:https://blog.csdn.net/john9925/article/details/108810556

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值