给定一个 x 轴上的线段数组 arr[]和一个整数 K ,任务是计算选择K条线段的方法数量,以便它们在任何点相交。由于答案可能很大,请将其打印为模 10^9+7。
例子:
Input: arr[] = [[1, 3], [4, 5], [5, 7]], K = 2
Output: 2
Explanation:
The first way to choose [1, 3], [4, 5] and the second way is [1, 3], [5, 7].Since Intersection of [4, 5], [5, 7] is not zero and hence cannot be included in answer.
Input: [[3, 7], [1, 4], [6, 9], [8, 13], [9, 11]], K = 1
Output: 0
Explanation:
Since we are only looking for single line segment, but for every single line segment Intersection is always non empty.
方法:
为了解决上面提到的问题,我们将尝试找出奇数案例的数量,即那些交集非空的案例。很明显,我们的答案将是Total Case – Odd Case。
要计算案例总数,请遵循以下方法:
- 可能的总案例是“n 选择 k”或n C k
- 我们预先计算所需数字的逆和阶乘以计算n C k
- 在 O(1) 时间内
- K 线段相交,好像 min(R1, R2, .., R{k-1}) >= Li,其中线段 [Li, Ri] 正在考虑中。维护一个multiset,维护秩序。首先,按照 Li 的升序对段进行排序。如果 Li 相同,则 Ri 较小的部分首先出现。
对于每个线段 [Li, Ri],遵循以下方法来找到奇数个案例的数量。
- 虽然多重集不为空,并且线不相交,然后从多重集中删除具有最小 Ri 的线并再次检查。
- 使用该段 [Li, Ri] 的违规方式数为p C k-1
- 其中 p = size_of_multiset。
- 在多重集中插入此线段的端点。
下面是上述方法的实现:
C++
// C++ program to find Number of ways
// to choose K intersecting
// line segments on X-axis
#include
using namespace std;
const long long mod = 1000000007;
const int MAXN = 1001;
long long factorial[MAXN], inverse[MAXN];
// Function to find (a^b)%mod in log b
long long power(long long a, long long b)
{
long long res = 1;
// Till power becomes 0
while (b > 0) {
// If power is odd
if (b % 2 == 1) {
res = (res * a) % mod;
}
// Multiply base
a = (a * a) % mod;
// Divide power by 1
b >>= 1;
}
return res;
}
// Function to find nCk
long long nCk(int n, int k)
{
// Base case
if (k < 0 || k > n) {
return 0;
}
// Apply formula to find nCk
long long ans = factorial[n];
ans = (ans * inverse[n - k]) % mod;
ans = (ans * inverse[k]) % mod;
return ans;
}
// Function to find the number of ways
void numberOfWays(vector > lines, int K,
int N)
{
// sort the given lines
sort(lines.begin(), lines.end());
// Find the number of total case
long long total_case = nCk(N, K);
// Declare a multiset
multiset m;
// loop till N
for (int i = 0; i < N; i++)
{
// Check if smallest element is
// smaller than lines[i]
while (!m.empty()
&& (*m.begin() < lines[i].first)) {
// Erase first element
m.erase(m.begin());
}
// Exclude the odd cases
total_case -= nCk(m.size(), K - 1);
// Modulus operation
total_case += mod;
total_case %= mod;
// Insert into multiset
m.insert(lines[i].second);
}
cout << total_case << endl;
}
// Function to precompute
// factorial and inverse
void preCompute()
{
long long fact = 1;
factorial[0] = 1;
inverse[0] = 1;
// Pre-compute factorial and inverse
for (int i = 1; i < MAXN; i++) {
fact = (fact * i) % mod;
factorial[i] = fact;
inverse[i] = power(factorial[i], mod - 2);
}
}
// Driver code
int main()
{
int N = 3, K = 2;
vector > lines;
// Function to pre-compute
// factorial and inverse
preCompute();
lines.push_back({ 1, 3 });
lines.push_back({ 4, 5 });
lines.push_back({ 5, 7 });
numberOfWays(lines, K, N);
return 0;
}
Java
// Java program to find Number of ways
// to choose K intersecting line
// segments on X-axis
import java.util.*;
import java.lang.*;
class GFG {
static long mod = 1000000007;
static int MAXN = 1001;
static long factorial[] = new long[MAXN],
inverse[] = new long[MAXN];
// Function to find (a^b)%mod in log b
static long power(long a, long b)
{
long res = 1;
// Till power becomes 0
while (b > 0) {
// If power is odd
if (b % 2 == 1) {
res = (res * a) % mod;
}
// Multiply base
a = (a * a) % mod;
// Divide power by 1
b >>= 1;
}
return res;
}
// Function to find nCk
static long nCk(int n, int k)
{
// Base case
if (k < 0 || k > n) {
return 0;
}
// Apply formula to find nCk
long ans = factorial[n];
ans = (ans * inverse[n - k]) % mod;
ans = (ans * inverse[k]) % mod;
return ans;
}
// Function to find the number of ways
static void numberOfWays(ArrayList lines, int K,
int N)
{
// sort the given lines
Collections.sort(lines, (a, b) -> a[0] - b[0]);
// Find the number of total case
long total_case = nCk(N, K);
// Declare a multiset
PriorityQueue m = new PriorityQueue<>();
// Loop till N
for (int i = 0; i < N; i++) {
// Check if smallest element is
// smaller than lines[i]
while (!m.isEmpty()
&& (m.peek() < lines.get(i)[0])) {
// Erase first element
m.poll();
}
// Exclude the odd cases
total_case -= nCk(m.size(), K - 1);
// Modulus operation
total_case += mod;
total_case %= mod;
// Insert into multiset
m.add(lines.get(i)[1]);
}
System.out.println(total_case);
}
// Function to precompute
// factorial and inverse
static void preCompute()
{
long fact = 1;
factorial[0] = 1;
inverse[0] = 1;
// Pre-compute factorial and inverse
for (int i = 1; i < MAXN; i++) {
fact = (fact * i) % mod;
factorial[i] = fact;
inverse[i] = power(factorial[i], mod - 2);
}
}
// Driver code
public static void main(String[] args)
{
int N = 3, K = 2;
ArrayList lines = new ArrayList<>();
// Function to pre-compute
// factorial and inverse
preCompute();
lines.add(new int[] { 1, 3 });
lines.add(new int[] { 4, 5 });
lines.add(new int[] { 5, 7 });
numberOfWays(lines, K, N);
}
}
// This code is contributed by offbeat
2
时间复杂度: O(MAXN * log(MAXN) + N * log(N))。
辅助空间: O(MAXN + N)。