Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
Ignore the ancient-tablet flavor text. You are counting subarrays with two restrictions: distinct count equals , and length lies in .
“Exactly distinct” is usually easier as at most k minus at most k-1. That removes the annoying equality condition.
Now add the length condition by counting atMost(K, X): subarrays with at most distinct values and length at most .
For each right endpoint, use a sliding left pointer so the window has at most distinct values. The length limit says the start must also be at least .
For fixed right, valid starts are from through right. So add right - max(left, right-X+1) + 1. Final answer is .
We need count subarrays satisfying two things:
Trying to maintain both “exactly ” and “length in range” directly is doable, but it gets fiddly. The clean trick is to count a softer condition and subtract.
Step 1: Replace exactly with at most
Let:
Then the number of subarrays with exactly distinct values and length at most is:
Because at most k includes everything with distinct values, and at most k-1 removes all the ones that are not exactly .
Now we also need length between and , so subtract the ones with length at most :
Rearranged:
That is the whole math. Not magic, just subtraction doing unpaid labor.
Step 2: Compute with two pointers
We need count subarrays with:
Fix the right endpoint right.
Maintain a sliding window [left, right] such that it has at most distinct values. When adding a[right] makes the distinct count too large, move left forward until the window is valid again.
After that, every start position s >= left gives a subarray [s, right] with at most distinct values.
But we also need length at most :
So:
Therefore the valid starts for this right are:
The number of those starts is:
if the interval is nonempty.
Since left <= right after the sliding window is fixed, and for real calls, this formula works cleanly. For safety, return 0 when or .
Coordinate compression
The values can be up to , so using them directly as indices would be dumb. Compress them to 0..m-1, then use a frequency vector.
Complexity
Each call to moves each pointer at most times, so it is after compression.
We call it four times, still per test case. Compression costs .
Total complexity:
per test case, with total , easily fine.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
ll countAtMost(const vector<int>& a, int kinds, int maxLen, int m) {
if (kinds <= 0 || maxLen <= 0) return 0;
vector<int> freq(m, 0);
int left = 0, distinct = 0;
ll ans = 0;
for (int right = 0; right < (int)a.size(); right++) {
if (freq[a[right]]++ == 0) distinct++;
while (distinct > kinds) {
if (--freq[a[left]] == 0) distinct--;
left++;
}
int firstStart = max(left, right - maxLen + 1);
ans += right - firstStart + 1;
}
return ans;
}
int main() {
setIO();
int t;
cin >> t;
while (t--) {
int n, k, l, r;
cin >> n >> k >> l >> r;
vector<long long> raw(n), vals;
for (auto &x : raw) {
cin >> x;
vals.push_back(x);
}
sort(vals.begin(), vals.end());
vals.erase(unique(vals.begin(), vals.end()), vals.end());
vector<int> a(n);
for (int i = 0; i < n; i++) {
a[i] = lower_bound(vals.begin(), vals.end(), raw[i]) - vals.begin();
}
int m = vals.size();
ll ans = countAtMost(a, k, r, m)
- countAtMost(a, k, l - 1, m)
- countAtMost(a, k - 1, r, m)
+ countAtMost(a, k - 1, l - 1, m);
cout << ans << '\n';
}
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
ll countAtMost(const vector<int>& a, int kinds, int maxLen, int m) {
if (kinds <= 0 || maxLen <= 0) return 0;
vector<int> freq(m, 0);
int left = 0, distinct = 0;
ll ans = 0;
for (int right = 0; right < (int)a.size(); right++) {
if (freq[a[right]]++ == 0) distinct++;
while (distinct > kinds) {
if (--freq[a[left]] == 0) distinct--;
left++;
}
int firstStart = max(left, right - maxLen + 1);
ans += right - firstStart + 1;
}
return ans;
}
int main() {
setIO();
int t;
cin >> t;
while (t--) {
int n, k, l, r;
cin >> n >> k >> l >> r;
vector<long long> raw(n), vals;
for (auto &x : raw) {
cin >> x;
vals.push_back(x);
}
sort(vals.begin(), vals.end());
vals.erase(unique(vals.begin(), vals.end()), vals.end());
vector<int> a(n);
for (int i = 0; i < n; i++) {
a[i] = lower_bound(vals.begin(), vals.end(), raw[i]) - vals.begin();
}
int m = vals.size();
ll ans = countAtMost(a, k, r, m)
- countAtMost(a, k, l - 1, m)
- countAtMost(a, k - 1, r, m)
+ countAtMost(a, k - 1, l - 1, m);
cout << ans << '\n';
}
}