题目大意
在长为 $n$ 的序列 $A$,问有多少区间 $[l,r]$ 满足区间众数的出现次数严格大于 $\frac{r-l+1}{2}$。
分析
我发现我真的不会数据结构,只会推推式子啥的,这种要想的题根本想不来。
设区间 $[l,r]$ 中存在众数 $w$(显然满足题意必唯一),有
$$ \sum_{i=l}^r [a_i=w] > \frac{r-l+1}{2} $$
分离变量,可以得到
$$ 2\sum_{i=1}^l [a_i=w] - l < 2\sum_{i=1}^r [a_i=w] - r $$
考虑设置函数
$$ S_w(x) = 2\sum_{i=1}^x [a_i = w] - x = \sum_{i=1}^x [a_i = w] - \sum_{i=1}^x [a_i \ne w] $$
观察 $S_w(x)$ 的特性,即可发现其只由 $1, -1$ 组成,可以转化为二阶前缀和问题。
解释待补充。
template <class T>
struct fwtree_2 {
fwtree<T> f1, f2, f3;
vector<T> u;
fwtree_2(int n = 0) : f1(n), f2(n), f3(n), u(n) {}
template <class iter>
void init(iter first, iter last) {
copy(first, last, u.begin());
T sum = u[0];
for (int i = 1; i < u.size(); i++) {
u[i] += u[i - 1] + sum;
sum += u[i];
}
}
void add(int l, int r, const T &t) {
r++;
f1.add(l, t), f1.add(r, -t);
f2.add(l, t * l), f2.add(r, -t * r);
f3.add(l, t * l * l), f3.add(r, -t * r * r);
}
T sum(int i) const {
T ret = u[i] + f1.sum(i) * (i + 1) * (i + 2);
ret += -f2.sum(i) * (2 * i + 3) + f3.sum(i);
return ret / 2;
}
T sum(int l, int r) const {
return sum(r) - sum(l - 1);
}
};
using pii = pair<int, int>;
int main() {
int n, type_;
cin >> n >> type_;
vector<vector<int>> B(n + 1);
vector<int> a(n + 1);
for (int i = 1; i <= n; i++) {
cin >> a[i];
B[a[i]].push_back(i);
}
ll ans = 0;
const int off = n + 3;
fwtree_2<ll> tr(n * 2 + 5);
for (int i = 0; i < n; i++) {
if (B[i].empty()) {
continue;
}
B[i].push_back(n + 1);
int last = 0, past_bi = 0;
vector<pii> v;
for (auto bi : B[i]) {
int dif = bi - past_bi;
int x = last - (dif - 1), y = last;
ans += tr.sum(x - 1 + off, y - 1 + off);
tr.add(x + off, y + off, 1);
v.emplace_back(x + off, y + off);
past_bi = bi, last -= dif - 2;
}
for (auto [x, y] : v) {
tr.add(x, y, -1);
}
}
cout << ans;
return 0;
}
全部代码请看:Luogu/4x/P4062.cpp。