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;
}

浙公网安备 33010602011771号