题目大意 给定数组 $a_i$,$q$ 次询问,每次询问是一个非负整数 $k$,求出有多少对 $(l, r)$,满足 $\max(a[i]) - \min(a[j]) > k$,其中 $l \le i, j \le r$。
题目链接
思路 不难发现满足要求的序列有单调性,即如果当前区间满足最大值减去最小值大于k,那么包含这个区间的更大的区间,也一定满足 。
而这一类问题,通常可以采用尺取法。即:
我们先固定起点 $l$,然后让 $r$ 从 $l$ 开始一个一个往后走,并记录最大值与最小值。
一旦当前序列满足了条件,那么选取 $r$ 之后的点作为结尾,也一定会满足,所以直接让答案 $ans\ \mathrel{+}= n - r + 1$,然后让 $l$ 后移动一位。
因为 $r$ 在恰好满足条件的时候就不再移动了,所以 $l$ 在往后移动一位的时候,满足条件的结尾一定在 $r$ 点或之后,所以 $r$ 的起点还是当前位置,然后继续按照第一步继续,直到统计完成。
因为我们需要记录区间的最大值和最小值,所以我们可以用两个单调队列来统计,即统计最大值的时候,如果新加入的数 $X$ 比当前的数 $Y$ 要大,那么就让 $Y$ 出队,因为$X$ 比 $Y$ 大还比它靠后,意味着在取最大值的时候,只要有 $X$ 在,就永远不会取到 $Y$,而 $X$ 又在 $Y$ 之后,也就是说它出队也晚于 $Y$,所以 $Y$ 就没有存在的必要了(惨 Y 惨) 。
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 #include <cstdio> #include <iostream> #include <deque> #include <cstring> #include <algorithm> using namespace std;const int maxN = 1e5 + 7 ;typedef long long ll;int m, n, a[maxN];ll calc (ll k) { deque<int > maxPos, minPos; int l = 1 ,r = 0 ; ll ans = 0 ; while (l <= n && r <= n) { while ((!maxPos.empty ()) && maxPos.front () < l) maxPos.pop_front (); while ((!minPos.empty ()) && minPos.front () < l) minPos.pop_front (); if ((!maxPos.empty ()) && a[maxPos.front ()] - a[minPos.front ()] > k) { ans += n - r + 1 ; ++l; continue ; } else { ++r; while (!maxPos.empty () && a[maxPos.back ()] <= a[r]) maxPos.pop_back (); maxPos.push_back (r); while (!minPos.empty () && a[minPos.back ()] >= a[r]) minPos.pop_back (); minPos.push_back (r); } } return ans; } int main () { scanf ("%d%d" , &n, &m); for (int i = 1 ; i <= n; ++i) scanf ("%d" , &a[i]); for (int i = 1 ; i <= m; ++i) { int k; scanf ("%d" , &k); printf ("%lld\n" , calc (k)); } return 0 ; }