CF1893D Colorful Constructive 题解

Description

你有 nn 个有颜色的立方体,第 ii 个立方体的颜色为 aia_i

你需要将所有立方体分配到若干个架子上。总共有 mm 个架子,第 ii 个架子可以放 sis_i 个立方体。同时,满足 s1+s2++sm=ns_1 + s_2 + \ldots + s_m = n

假设某个容量为 kk 的架子上,依次放置了颜色为 c1,c2,,ckc_1, c_2, \ldots, c_k 的立方体。我们定义该架子的“多彩度”为架子上相同颜色的两个立方体之间的最小距离。如果架子上的所有立方体颜色都不同,则多彩度被认为等于架子的容量 kk

更正式地,c1,c2,,ckc_1, c_2, \ldots, c_k 的多彩度定义如下:

  • 如果 c1,c2,,ckc_1, c_2, \ldots, c_k 的颜色都不同,则多彩度为 kk
  • 否则,多彩度为最小的整数 x1x \geq 1,使得存在下标 ii (1ikx)(1 \leq i \leq k - x) 满足 ci=ci+xc_i = c_{i+x}

对于每个架子,给定了最小要求的多彩度,即给定了 d1,d2,,dmd_1, d_2, \ldots, d_m,表示第 ii 个架子的多彩度必须 di\geq d_i

请你将所有立方体分配到各个架子上,使得每个架子的多彩度都满足要求,或者报告无法做到。

1n,m2×1051\leq n,m\leq 2\times 10^5

Solution

对于架子 ii 先分 sidi\left\lfloor\frac{s_i}{d_i}\right\rfloor 个大小为 did_i 的块和一个大小为 simoddis_i\bmod d_i 的块,容易发现每个块内的元素不能相同。

然后经过手玩会发现只要满足每个块内元素不相同就一定能构造。证明就考虑对于一个给定的颜色方案,求出其可能的最大的多彩度。

nn 为元素总数,mxmx 为众数出现次数,cnticnt_i 表示出现次数为 ii 的颜色数量。对于出现次数为 mxmx 的一定是分 mxmx 组,每组的排列顺序相同。然后让出现次数 [1,mx1][1,mx-1] 内的数去填 mx1mx-1 个间隔,所以多彩度的理论最大值是 cntmx+nmxcntmxmx1=ncntmxmx1cnt_{mx}+\frac{n-mx\cdot cnt_{mx}}{mx-1}=\frac{n-cnt_{mx}}{mx-1}。构造考虑按照出现次数从大到小依次放到间隔中,且第 ii 个插入的颜色需要接着第 i1i-1 个颜色的末尾往后加。

由于 cntmxsimoddicnt_{mx}\leq s_i\bmod d_i,所以 sicntmxmx1di\frac{s_i-cnt_{mx}}{mx-1}\geq d_i,也就一定能构造。


对于把颜色放到架子上,由于所有架子的块互相独立,所以维护一个优先队列表示每个块的长度,然后每次选择当前出现次数最多的块加入当前颜色即可。

把每个架子的每种颜色出现次数求出来后按照证明中的构造即可。

时间复杂度:O((n+m)logn)O((n+m)\log n)

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <bits/stdc++.h>

// #define int int64_t

const int kMaxN = 2e5 + 5;

int n, m;
int a[kMaxN], cnt[kMaxN], sz[kMaxN], d[kMaxN];
std::vector<int> vec[kMaxN];

void dickdreamer() {
std::cin >> n >> m;
std::fill_n(cnt + 1, n, 0);
for (int i = 1; i <= m; ++i) vec[i].clear();
std::priority_queue<std::pair<int, int>> q;
for (int i = 1; i <= n; ++i) std::cin >> a[i], ++cnt[a[i]];
for (int i = 1; i <= m; ++i) std::cin >> sz[i];
for (int i = 1; i <= m; ++i) {
std::cin >> d[i];
for (int j = 1; j <= sz[i] / d[i]; ++j) q.emplace(d[i], i);
if (sz[i] % d[i]) q.emplace(sz[i] % d[i], i);
}
for (int i = 1; i <= n; ++i) {
std::vector<std::pair<int, int>> vv;
for (int j = 1; j <= cnt[i]; ++j) {
if (!q.size()) return void(std::cout << "-1\n");
auto [l, id] = q.top(); q.pop();
--l, vec[id].emplace_back(i);
if (l) vv.emplace_back(l, id);
}
for (auto p : vv) q.emplace(p);
}
for (int i = 1; i <= m; ++i) {
static int cnt[kMaxN] = {0};
std::vector<int> col;
for (auto x : vec[i]) {
if (!cnt[x]++) col.emplace_back(x);
}
std::sort(col.begin(), col.end(), [&] (int i, int j) { return cnt[i] > cnt[j]; });
std::vector<std::vector<int>> res(cnt[col[0]]);
int now = 0;
for (auto x : col) {
int lim = (cnt[x] == res.size() ? res.size() : res.size() - 1);
for (int c = 1; c <= cnt[x]; ++c, now = (now + 1) % lim) {
assert(now < res.size());
res[now].emplace_back(x);
}
}
for (auto &vec : res) {
for (auto x : vec) std::cout << x << ' ';
}
std::cout << '\n';
for (auto x : vec[i]) --cnt[x];
}
}

int32_t main() {
#ifdef ORZXKR
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
int T = 1;
std::cin >> T;
while (T--) dickdreamer();
// std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
return 0;
}

CF1893D Colorful Constructive 题解
https://sobaliuziao.github.io/2025/09/22/post/d2fa522.html
作者
Egg_laying_master
发布于
2025年9月22日
许可协议