the way it starts and the way it ends

P8830 众数。

困难的根号分治题目。

看到众数,肯定要考虑根号分治。不难想到的策略是对着出现次数进行根号分治,分为 \(\ge \sqrt n\) 和 \(< \sqrt n\)。我们把前者称为大数,后者称为小数。

先考虑转化问题,不难考虑为在一个序列上选定一个操作区间,答案就是非操作区间的众数的出现次数+操作区间的众数的出现次数。我们定义 \(x\) 为非操作区间内的众数,\(y\) 为操作区间内的众数。

考虑分讨。

\(x\) 为大数,\(y\) 为小数,考虑转化贡献,为 \(cnt_x - cnt_{x_{in}} + cnt_{y_{in}}\),其中,\(in\) 表示的是在操作区间内的数。因此我们考虑对于后者做最大子段和,具体的,对于每一个 \(x\),枚举 \(y\),显然只有 \(y\) 的出现点为关键点,\(x\) 可以做前缀和,复杂度 \(O(n \sqrt n\))。

\(x\) 为小数,\(y\) 为大数,同样考虑转化贡献,为 \(cnt_x + cnt_{y_{in}} - cnt_{x_{in}}\)。因此我们同样可以枚举 \(x\),显然也是可以以 \(x\) 的出现位置作为关键点,做最大子段和的。两部分是类似的。

\(x\) 为小数,\(y\) 为小数,我们不妨枚举 \(x\),一个关键的引理是操作的区间是贴着 \(x\) 的出现位置的,否则我们可以扩大操作区间,显然不会影响到 \(x\) 在区间外的出现次数,而区间内的众数出现次数是只可能扩大的。所以这样的区间个数是 \(\sum {cnt_i}^2\) 级别的,而 \(cnt \le B\),故原式 \(\le n \cdot B\)。因此我们证明了区间个数是根号级别的。问题转化为如何快速求出一个区间内的众数。

考虑 \(y\) 也是小数,我们不妨从此入手,获得众数为某个特定值的存在区间。进一步的,我们设计 \(f[k][i]\),表示从 \(i\) 出发的区间,众数大小为 \(k\) 的最小的 \(r\)。这个是可以对于每一个 \(k\) 双指针解决的。然后再考虑查询,不难发现对于序列的每一个位置 \(i\),我们至多只会有根号次查询以 \(i\) 为左端点,因此也是可以双指针的。具体的,一个指针对应的是 \(r\),这个根据上面的分析是单调递增的,另一个指针对应的是 \(k\),显然随着 \(r\) 的增加,是不降的。

所以,总体的时间复杂度是 \(O(n \sqrt n)\)。

Code

不要忘记考虑边界了,也就是第一个 \(pos\) 之前和最后一个 \(pos\) 之后。

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define File(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout)
#define LL long long
#define fi first
#define se second
const int N = 2e5 + 10,K = 1000;
vector<int> pos[N];
int a[N],lsh[N];
int sum[N];
int cnt[N];
int f[K][N];
int ban[N];
vector<int> ans_pos;
void solve(){
	int n;
	cin >> n;
	for(int i=1;i<=n;i++){
		cin >> a[i];
		lsh[i] = a[i];
	}
	sort(lsh+1,lsh+1+n);
	int len = unique(lsh+1,lsh+1+n) - lsh - 1;
	for(int i=1;i<=n;i++){
		a[i] = lower_bound(lsh+1,lsh+1+len,a[i]) - lsh;
		pos[a[i]].push_back(i);
	}
	int B = sqrt(n) + 1;
	for(int i=1;i<=B;i++)
		fill(f[i]+1,f[i]+1+n,0);
	fill(ban+1,ban+1+len,0);
	int ans = 0;
	for(int i=1;i<=len;i++){
		int res = 0;
		if(pos[i].size() >= B){
			sum[0] = 0;
			ban[i] = 1;
			res = max(res,(int)pos[i].size());
			for(int j=1;j<=n;j++)
				sum[j] = sum[j-1] + (a[j] == i);
			// x not op
			for(int j=1;j<=len;j++){
				int pre,nw,mx;
				pre = nw = mx = 0;
				if(j == i) continue;
				for(int v : pos[j]){
					nw -= sum[v] - sum[pre];
					if(nw < 0) nw = 0;
					nw ++ ;
					mx = max(mx,nw);
					pre = v;
				}
				res = max(res,mx + (int)pos[i].size());
			}
			// x is op,y is not op
			if(res > ans){
				ans = res;
				ans_pos.clear();
				ans_pos.push_back(i);
			}
			else if(ans == res)
				ans_pos.push_back(i);
			for(int j=1;j<=len;j++){
				int pre = 0,mx = 0,nw = 0;
				if(j == i) continue;
				for(int v : pos[j]){
					nw += sum[v] - sum[pre];
					mx = max(mx,nw);
					nw -- ;
					if(nw < 0) nw = 0;
					pre = v;
				}
				nw += sum[n] - sum[pre];
				mx = max(mx,nw);
				if(nw < 0) nw = 0;
				if(mx + (int)(pos[j].size()) > ans){
					ans = mx + (int)(pos[j].size());
					ans_pos.clear();
					ans_pos.push_back(j);
				}
				else if(mx + (int)(pos[j].size()) == ans)
					ans_pos.push_back(j);
			}
		}
	}
	// x < B,y < B
	for(int k=1;k<=B;k++){
		int L = 1,R = 0;
		fill(cnt+1,cnt+1+len,0);
		int fl = 0;
		while(R <= n){
			if(!fl && R == n){
				while(L <= n){
					f[k][L] = n + 1;
					L ++ ;
				}
				break;
			}
			if(!fl && R < n){
				R ++ ;
				if(!ban[a[R]]){
					cnt[a[R]] ++ ;
					if(cnt[a[R]] == k) fl ++ ;
				}
			}
			else{
				if(!ban[a[L]]){
					if(cnt[a[L]] == k) fl -- ;
					cnt[a[L]] -- ;
				}
				f[k][L] = R;
				L ++ ;
			}
		}
	}
	for(int i=1;i<=len;i++){
		int res = 0;
		if(pos[i].size() >= B) continue;
		res = max(res,(int)(pos[i].size()));
		for(int j=0;j<pos[i].size();j++){
			int k = 0;
			for(int l=j+1;l<pos[i].size();l++){
				int x = pos[i][j],y = pos[i][l];
				if(x == y - 1) continue;
				while(k <= B && f[k][x+1] < y) k ++ ;
				k -- ;
				res = max(res,(int)(pos[i].size() - (l - j - 1) + k));
			}
			if(pos[i][j] < n){
				while(k <= B && f[k][pos[i][j]+1] <= n) k ++ ;
				k -- ;
				res = max(res,j + 1 + k);
			}
		}
		if(pos[i][0] > 1){
			int k = 0;
			for(int l=0;l<pos[i].size();l++){
				int x = 0,y = pos[i][l];
				while(k <= B && f[k][x+1] < y) k ++ ;
				k -- ;
				res = max(res,(int)(pos[i].size() - l + k));
			}
		}
		if(ans < res){
			ans = res;
			ans_pos.clear();
			ans_pos.push_back(i);
		}
		else if(ans == res)
			ans_pos.push_back(i);
	}

	cout << ans << "\n";
	sort(ans_pos.begin(),ans_pos.end());
	ans_pos.erase(unique(ans_pos.begin(),ans_pos.end()),ans_pos.end());
	for(int x : ans_pos)
		cout << lsh[x] << "\n";
	ans_pos.clear();
	for(int i=1;i<=len;i++)
		pos[i].clear();
}
int main(){
	IOS;
	int T;
	cin >> T;
	while(T -- )
		solve();
	return 0;
}
posted @ 2026-09-30 10:16  WinterXorSnow  阅读(5)  评论(0)    收藏  举报