Loading

CF1446D2 Frequency Problem - 数据结构

题意

给定正整数数列 \(\{a_n\}\),求最长的子区间的长度,使得这个区间内有至少两种出现次数最多的数。

\(1\le n\le 2\times 10^5\)

题解

来自 lxl 的 \(1\log\) 做法!不过在这个数据范围下并无优势。

定义一个区间是合法的,当且仅当其中有至少两种出现次数最多的数。

首先,找到全局的众数 \(m\)\(m\) 一定是答案区间的两个众数之一。因为如果一个区间内 \(m\) 的出现次数不是最多的,那我们一定可以向外扩充区间,找到更大的一个合法区间。

我们枚举一个 \(x(x\neq m)\),并计算以 \(x,m\) 为众数的最大区间。设 \(x\) 的全局出现次数为 \(c(x)\),若我们能在 \(\mathcal{O}(c(x)\log n)\) 的复杂度内计算这个,问题就解决了。

我们将 \(x\) 的所有出现位置从小到大排序。维护 \(m\) 的出现位置的集合 \(S\),按顺序枚举 \(x\) 的所有出现位置 \(p_i\),并将 \(S\)\(>p_i\) 且最小的元素标记,然后删除。然后我们倒序枚举 \(x\) 的出现位置,对于 \(S\) 中的每个前驱做一遍这个操作。

例如,对于 mxxmm 这个序列,我们会让第一个 \(x\) 标记第二个 \(m\),第二个 \(x\) 标记第一、三个 \(m\)

这样每个 \(x\) 的出现位置都标记了不超过两个 \(m\),总的个数是 \(\mathcal{O}(c(x))\) 的。对于那些没被标记的 \(m\),我们一定不能让它出现在答案区间中。所以它们充当了分隔符的作用,对于每两个相邻的分隔符之间,计算最长的合法区间即可。

复杂度 \(\mathcal{O}(\sum_x c(x)\log n)=\mathcal{O}(n\log n)\)

代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;
#define For(Ti,Ta,Tb) for(int Ti=(Ta);Ti<=(Tb);++Ti)
#define Dec(Ti,Ta,Tb) for(int Ti=(Ta);Ti>=(Tb);--Ti)
#define Debug(...) fprintf(stderr,__VA_ARGS__)
typedef long long ll;
const int N=2e5+5;
int n,a[N],cnt[N];
vector<int> occ[N];
struct Point{int p,v;};
bool operator<(const Point &p1,const Point &p2){
	return p1.p<p2.p;
}
bool operator==(const Point &p1,const Point &p2){
	return p1.p==p2.p&&p1.v==p2.v;
}
bool Between(int mode,int x,int y){
	auto it=upper_bound(occ[mode].begin(),occ[mode].end(),x);
	return it!=occ[mode].end()&&*it<y;
}
int val[N*2],tot,tm[N*2];
int main(){
	ios::sync_with_stdio(false),cin.tie(nullptr);
	cin>>n;
	For(i,1,n){
		cin>>a[i];
		++cnt[a[i]],occ[a[i]].push_back(i);
	}
	int mode=max_element(cnt+1,cnt+n+1)-cnt,ans=0;
	set<int> st(occ[mode].begin(),occ[mode].end());
	vector<int> del;
	For(x,1,n){
		if(x==mode||!cnt[x]) continue;
		for(int i:del) st.insert(i);
		del.clear();
		vector<Point> tg;
		for(int i:occ[x]){
			auto it=st.upper_bound(i);
			if(it!=st.end()) tg.push_back({*it,-1}),del.push_back(*it),st.erase(it);
			tg.push_back({i,1});
		}
		for(int i=occ[x].size()-1;i>=0;--i){
			auto it=st.lower_bound(occ[x][i]);
			if(it!=st.begin()) tg.push_back({*--it,-1}),del.push_back(*it),st.erase(it);
		}
		sort(tg.begin(),tg.end());
		tg.erase(unique(tg.begin(),tg.end()),tg.end());
		for(auto i=tg.begin();i!=tg.end();++i){
			auto l=i;
			for(;next(i)!=tg.end()&&!Between(mode,i->p,next(i)->p);++i);
			int lim,rim;
			auto it=lower_bound(occ[mode].begin(),occ[mode].end(),l->p),itr=upper_bound(occ[mode].begin(),occ[mode].end(),i->p);
			if(it==occ[mode].begin()) lim=0;
			else lim=*--it;
			if(itr==occ[mode].end()) rim=n;
			else rim=*itr-1;
			++tot,val[0+n]=lim,tm[0+n]=tot;
			int cur=0;
			for(auto j=l;j<=i;++j){
				cur+=j->v;
				if(tm[cur+n]==tot) ans=max(ans,(j==i?rim:next(j)->p-1)-val[cur+n]);
				else val[cur+n]=j->p,tm[cur+n]=tot;
			}
		}
	}
	cout<<ans<<'\n';
	return 0;
}
posted @ 2022-01-08 17:28  Alan_Zhao_2007  阅读(90)  评论(0编辑  收藏  举报