CodeForces- Longest Strike 题解

题目

题目分析

给你一个长度为 \(n\) 的序列 \(a\) 和一个整数 \(k\),你要求一个区间 \([l,r]\) 满足:

  • 对于任何整数 \(x∈[l,r]\)\(x\)\(a\) 中的出现次数不少于 \(k\) 次。
  • 最大化 \(r-l\)

无解输出 -1

请注意, \(x∈[l,r]\) 每一个数都要满足次数大于\(k\) 次。

做题思路

首先看到时间限制是一秒,我们先想到暴力的做法就是循环枚举,很明显超时,所以我们要思考是不是要优化掉第二层寻找,很明显,我们可以思考到由于是连续的一段,前后就必须相差为 \(1\),我们不妨把他排序好,时间是 \(\mathcal{O(nlogn)。}\) 因为 \(map\) 这些容器都是带 \(log\) 的。


我没用 \(sort\),使用 \(set\) 来存放数据再导入到 \(vector\)里面去。不过时间上没那么快,因为 \(stl\) 容器的特征。我一开始是因为 \(vector\) 开太大了导致以为使用 \(sort\) 出错,然后就改用了 \(set\) 。最后我们直接循环找到最长的一段存好,一旦中间断了就重开即可。

代码实现

代码简洁并配有注释

#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
int n;
int k;
int a[200005];
void solve() {
	cin >> n;
	cin >> k;
	map<int, int>ma;
	vector<int>v(200005);
	int tot = -1;//从0开始 因为++所以-1
	map<int, bool>vis;
	int ans = 0;
	set<int>s;
	int maxn = 0;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		ma[a[i]]++;
		if (ma[a[i]] >= k && vis[a[i]] == 0) {
			if (vis[a[i]])continue;
			s.insert(a[i]);
			vis[a[i]] = 1;
		}
	}
	for ( auto it = s.rbegin(); it != s.rend(); it++) {
		v[++tot] = *it;
	}
	if (tot == -1) {
		cout << -1 << endl;
		return ;
	}
	int r = v[0];
//	sort(v.begin(), v.end(), greater<int>());
	for (int i = 1; i <= tot; i++) {
		if (v[i - 1] - v[i ] == 1) {
			maxn++;//加1 说明连续
		} else {
			maxn = 0;//断了
		}
		if (maxn > ans) {
			ans = maxn;
			r = v[i];
		}
	}
	cout << r << " " << r + ans << endl;
	return ;
}
signed main() {
	int t;
	ios::sync_with_stdio();
	cin.tie(0);
	cout.tie(0);
	cin >> t;
	for (int i = 1; i <= t; i++)solve();
	return 0;
}
posted @ 2025-04-16 19:58  LteShuai  阅读(14)  评论(0)    收藏  举报