题目大意:给你一个长度为 $n$ 的序列,问有多少个区间 $[l,r]$ 满足 $a_l,a_{l+1},\cdots,a_r$ 这些数字最大值不超过最小值的 $k$ 倍。$n \leq 10^7$
$O(n \log n)$ 做法可以考虑 $min,max$ 前缀和是单调的,因此对于每个 $l$ 可以二分 $r$ 的位置,加上 RMQ 求区间最值即可。
满分做法,维护两个单调队列分别保存最大、最小值,尺取。
#include <cstdio>
#include <algorithm>
using std::max; using std::min;
int q1[1000000][2], head1 = 1, tail1; //max
int q2[1000000][2], head2 = 1, tail2; //min
int main() {
int n, k, seed, ll, rr, l, r; long long ans = 0;
scanf("%d%d%d%d%d", &n, &k, &seed, &ll, &rr);
for (l = 1, r = 1; r <= n; ++r) {
int now = seed % (rr - ll + 1) + ll;
seed = (13331ll * seed + 23333) % 1000000007;
while (head1 <= tail1 && max(now, q1[head1][1]) > 1LL * k * min(now, q2[head2][1])) {
ans += r - l, ++l;
if (q1[head1][0] < l) ++head1;
if (q2[head2][0] < l) ++head2;
}
while (head1 <= tail1 && q1[tail1][1] <= now) --tail1;
while (head2 <= tail2 && q2[tail2][1] >= now) --tail2;
q1[++tail1][0] = r, q1[tail1][1] = now;
q2[++tail2][0] = r, q2[tail2][1] = now;
}
for (; l <= n; ++l) ans += n - l + 1;
printf("%lld\n", ans);
return 0;
}
时间复杂度 $O(n)$