while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int main () {
int t = read();
while (t--) {
n = read();
for (int i = 1; i <= n; i++) a[i] = read();
for (int i = 1; i <= n; i++) {
if (s.empty() || a[i] < a[s.top()]) s.push(i);
else {
while (!s.empty() && a[i] >= a[s.top()]) {
rig[s.top()] = i;
s.pop();
}
s.push(i);
}
}
while (!s.empty()) rig[s.top()] = n + 1, s.pop();
for (int i = n; i; i--) {
if (s.empty() || a[i] < a[s.top()]) s.push(i);
else {
while (!s.empty() && a[i] >= a[s.top()]) {
lef[s.top()] = i;
s.pop();
}
s.push(i);
}
}
while (!s.empty()) lef[s.top()] = 0, s.pop();
long long ans = 0LL;
for (int i = 1; i <= n; i++) {
if (!lef[i] || a[lef[i]] != a[i]) ans += rig[i] - lef[i] - 2;
else ans += rig[i] - i - 1;
}
printf("%lld\n", ans);
}
return 0;
}
复制代码
G. The Median of the Median of the Median
总体思路:先二分最终的中位数,再判断现实中位数是否大于等于二分的中位数
利用 suma 数组记录 a 大于等于二分的中位数 x 的数目的前缀和。
记录 a 数组该区间内的中位数是否大于等于 x(如果 a 数组该区间内的中位数是大于等于 x的,那么至少有一半,即 个 a 要大于等于 x)。
同样记录对应区间内的中位数是否大于等于 x 且原理与 b 相同。
最后判断 c 数组中是否有凌驾一半的数是大于等于二分的中位数的。
c 数组的前缀和处理(根据样例 1 举例说明):1 3 1 7
b
1
2
3
4
1
1
1
1
1
2
3
1
3
3
1
1
4
7
c
1
2
3
4
1
1
1
1
1
2
3
1
1
3
1
1
4
7
以上是按照界说,b,c 数组对应区间内的中位数,两个数组存有数据的部分都类似于一个倒三角形。
可以发现原界说的 是 这个倒三角区域内全部的数中位数,这个倒三角恰好是以 (i,j)为右上角的倒三角。以是代码中 c 数组的每一个 记录的是:在原界说的 b 数组中,以(i,j)为右上角的倒三角区域内,大于等于二分的中位数x的数目。
#include <bits/stdc++.h>
using namespace std;
const int N = 2010;
int n, suma[N], a[N], b[N][N], c[N][N];
inline int read() {
int x = 0, f = 1; char c = getchar();
while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
bool check(int x) {
for (int i = 1; i <= n; i++) suma[i] = suma[i - 1] + (a[i] >= x);