カノジョの妹とキスをした。
引理:给定序列
a_1,a_2,\dots,a_n ,对于所有存在绝对众数的前缀,绝对众数的种类数O(\log n) 。证明:我们记
c_i 表示从前往后出现的第i 种绝对众数在第一次成为绝对众数时在前缀中的出现次数,显然有c_i>c_{i-1}>c_{i-2} ,但是他所在的前缀也包含了i-1,i-2 两种绝对众数,所以需要满足c_i>c_{i-1}+c_{i-2}>2c_{i-2} ,我们只考虑下标为奇数的子序列c_{2k+1} ,有c_{2k+1}>2c_{2k-1} ,由于最后一项应当小于等于n ,所以子序列长度至多\log n ,c 的长度也至多2\log n 。
考虑分治,对于一个跨越分治中心
判断一个数是否是一个区间的绝对众数只需要统计他在区间内出现了几次,对出现的所有数开 vector 记录出现的位置,二分查找即可求出。
#include <bits/stdc++.h>
#define LL long long
#define ull unsigned long long
#define uint unsigned int
using namespace std;
const int N = 1e6 + 10;
int n, m, A[N];
vector<int> vec[N]; unordered_map<int, int> idx;
bool check(int l, int r, int k) {
k = idx[k];
return 2 * (upper_bound(vec[k].begin(), vec[k].end(), r) - lower_bound(vec[k].begin(), vec[k].end(), l)) > r - l + 1;
}
LL Ans = 0; int cnt[N];
void Solve(int l, int r) {
if (l == r) { ++ Ans; return ; }
int mid = (l + r) >> 1;
vector<int> key;
for (int i = mid, t = 0, c = 0; i >= l; i --) {
if (!c) t = A[i], c = 1;
else c += (t == A[i] ? 1 : -1);
if (check(i, mid, t)) key.push_back(t);
}
for (int i = mid + 1, t = 0, c = 0; i <= r; i ++) {
if (!c) t = A[i], c = 1;
else c += (t == A[i] ? 1 : -1);
if (check(mid + 1, i, t)) key.push_back(t);
}
sort(key.begin(), key.end()); key.erase(unique(key.begin(), key.end()), key.end());
for (int x : key) {
int lim = (r - l + 1) / 2 + 5;
for (int i = mid, c = 0; i >= l; i --) {
c += (A[i] == x ? 1 : -1);
cnt[c + lim] ++;
}
for (int i = lim * 2; i >= 0; i --) cnt[i] += cnt[i + 1];
for (int i = mid + 1, c = 0; i <= r; i ++) {
c += (A[i] == x ? 1 : -1); Ans += cnt[lim - c + 1];
}
for (int i = 0; i <= lim * 2; i ++) cnt[i] = 0;
}
Solve(l, mid), Solve(mid + 1, r);
}
int main() {
ios::sync_with_stdio(false); cin.tie(0), cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i ++) cin >> A[i], idx[A[i]] = i;
for (int i = 1; i <= n; i ++) vec[idx[A[i]]].push_back(i);
Solve(1, n);
cout << Ans << "\n";
return 0;
}