1552E. Colors and Intervals
https://codeforces.com/contest/1552/problem/E
勉强还算在复建期内…但这场B卡死是真的“真有我的”,CD反而还好
题意:给出 n × k n \times k n×k 个数的颜色,(一共有n种颜色,每种颜色有k个数),要求输出n个区间 [ a i , b i ] [a_i, b_i] [ai,bi],第i个区间端点都是第i种颜色,并且每个数被包括的次数不能超过 ⌈ n k − 1 ⌉ \lceil \frac{n}{k - 1} \rceil ⌈k−1n⌉。
两种做法:
-
直接贪心,把每个区间和区间的颜色取出来,根据右端点排序, 每次能取就取
-
(1)考虑到每个被取的区间中端点的这个颜色不会在除了两端以外出现,每种颜色实际被分成了k-1个块。
(2)根据(1)中的块,第t块中取的每种颜色的区间的左端点为该颜色第t次出现的位置,对还没有选择的颜色的区间同样根据右端点排序,最多取 ⌈ n k − 1 ⌉ \lceil \frac{n}{k - 1} \rceil ⌈k−1n⌉个。
因为 , 在前一块里取的区间可能互相重合但他们不会和后一块里取的区间重合,因为(2)是根据右端点排序取的,在下一块里的左端点是上一块中的右端点,严格不重合。而由于 ⌈ n k − 1 ⌉ × ( k − 1 ) ≥ n \lceil \frac{n}{k - 1} \rceil \times (k - 1) \geq n ⌈k−1n⌉×(k−1)≥n , 一定能取完n种颜色, 很妙。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e4 + 10;
const int M = 110;
struct node {
int l, r;
int co, idx;
};
int c[N];
vector<int> g[M];
vector<node> vec[M];
bool vis[M];
pair<int, int> ans[N];
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int n, k;
cin >> n >> k;
for (int i = 0; i < n * k; ++i) {
cin >> c[i];
g[c[i]].push_back(i);
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j < k; ++j) {
vec[j].push_back({g[i][j - 1], g[i][j], i, j});
}
}
int ceil = (n + k - 2) / (k - 1);
for (int i = 1; i < k; ++i) {
sort(vec[i].begin(), vec[i].end(), [](node x, node y) { return x.r < y.r; });
int cnt = 0;
for (int j = 0; j < n; ++j) {
if(vis[vec[i][j].co]) continue;
vis[vec[i][j].co] = 1;
ans[vec[i][j].co] = {vec[i][j].l, vec[i][j].r};
cnt ++;
if(cnt >= ceil) break;
}
}
for(int i = 1; i <= n; ++ i) {
cout << ans[i].first + 1 <<" "<< ans[i].second + 1 << endl;
}
return 0;
}