Topics
We’re given n
points on the x-axis and a maximum distance d
. A triplet is valid if the difference between the largest and smallest point in the triplet is at most d
. Count valid triplets of points.
Idea
We need to count the number of ways to pick three distinct points such that the distance between the farthest two does not exceed . For each rightmost point , we need to count how many previous points and can form a valid triplet.
Approach 1: Sliding Window
We maintain a sliding window with two pointers:
- The right pointer iterates through the points.
- The left pointer moves forward to ensure that .
At each step, we count the number of valid pairs between and . The number of ways to pick two elements from this range is:
where . This efficiently calculates all valid triplets in time.
Approach 2: Binary Search
Instead of using two pointers, we can use binary search (lower bound) to efficiently find the smallest index such that . This allows us to find the range of valid points in per iteration, leading to an overall complexity of .
Both approaches are efficient, but two pointers is often simpler and runs in linear time.
Code
// Approach 1 (Sliding window)
void solve() {
int n, d;
cin >> n >> d;
ll ans = 0;
ll curr = 0;
int left = 0;
vector<ll> arr;
arr.pb(INT_MIN);
for (int i = 1; i <= n; ++i) {
cin >> curr;
arr.pb(curr);
while (left < i and curr - arr[left] > d) {
left++;
}
int choices = (i - 1 - left + 1);
ans += (1LL * choices * (choices - 1)) / 2;
}
cout << ans << endl;
}
// Approach 2 (Binary search)
void solve() {
int n, d;
cin >> n >> d;
ll ans = 0;
ll curr = 0;
vector<ll> arr;
arr.pb(INT_MIN);
for (int i = 1; i <= n; ++i) {
cin >> curr;
arr.pb(curr);
auto it = lower_bound(all(arr), curr - d);
int left = distance(arr.begin(), it); // gives index
if (left == i) {
continue;
}
int choices = (i - 1 - left + 1);
ans += (1LL * choices * (choices - 1)) / 2;
}
cout << ans << endl;
}