ABC429D
Solution
首先观察到池塘的周长很大,但是人数有限,所以首先对位置进行离散化并计数。
很明显朴素的做法 $\mathcal{O}(n^2)$ 无法通过,但是因为只需要求出对于每个 $i$ 的答案的和,故考虑从 $i$ 到 $i+1$ 的答案的变化。
很明显,$i$ 答案所包含的区间与 $i+1$ 答案所包含的区间一定重和,因为下一次不包含第 $i$ 个位置的人,但是总人数依然要比 $c$ 大,所以区间右端点一定往后移动,转化为双指针问题。每次移动累加答案即可。
Code
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
struct P { LL id, num; } p[500005];
LL n, m, c, a[500005], cnt, r, now, ans;
map<LL, LL> pl;
bool cmp(P x, P y) { return x.id < y.id; }
LL dis(LL l) {
if (l == cnt) return p[1].id + m - p[l].id;
return p[l + 1].id - p[l].id;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m >> c;
for (LL i = 1; i <= n; i++) {
cin >> a[i];
if (pl.count(a[i])) p[pl[a[i]]].num++;
else {
cnt++;
p[cnt].id = a[i];
p[cnt].num = 1;
pl[a[i]] = cnt;
}
}
sort(p + 1, p + cnt + 1, cmp);
r = 1; now = p[1].num;
for (LL l = 1; l <= cnt; l++) {
now -= p[l].num;
while (now < c) {
r++;
if (r > cnt) r -= cnt;
now += p[r].num;
}
ans += now * dis(l);
}
cout << ans;
}