题目链接:

https://codeforces.com/contest/1692/problem/H

题意:

长为 \(n\) 的序列,从中选择一个连续的子序列,使这个子序列中出现次数最多的数字的数量减去剩余数字的数量最大。

思路:

暴力的方法,枚举每一个区间,然后求该区间中出现次数最多的数字的数量,计算要求计算的最大值,显然超时。
反过来考虑,将所有有相同数字的下标存在一起,假设该数字就是出现次数最多的那个数字,那么求它出现次数减去剩余数字的数量的最大值,其实就是求该序列的最长子段和。
如果出现了,值就是 1,没出现,值就是 -1,对于两个下标之间的数的贡献,都是 -1,设序列为 \(b\),那么 \(b[i] - b[i - 1] - 1\) 就是中间数的数量,也就是前缀和要减去这么多。

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
void solve(){
	LL n;
	cin >> n;
	vector <LL> x(n);
	map <LL, vector <LL> > mp;
	for (int i = 0; i < n; i ++ ){
		cin >> x[i];
		mp[x[i]].push_back(i);
	}
	LL a, l, r, ans = -1e18;
	for (auto [t, b] : mp){
		LL m = b.size(), sum = 0, mn = 1e18, p = 0;
		for (int i = 0; i < m; i ++ ){
			if (i)
				sum -= b[i] - b[i - 1] - 1;
			if (sum < mn){
				mn = sum;
				p = b[i];
			}
			sum ++ ;
			if (sum - mn > ans){
				ans = sum - mn;
				a = t;
				l = p + 1;
				r = b[i] + 1;
			}
		}
	}
	cout << a << " " << l << " " << r << "\n";
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	LL T = 1;
	cin >> T;
	while (T -- )
		solve();
	return 0;
}
posted on 2022-06-18 12:26  Hamine  阅读(56)  评论(0编辑  收藏  举报