1 条题解
-
0
一、题意核心(根据代码反向推导)
给定一个长度为 的数组 ,要求构造一个数组 ,满足规则:
- 对于数值等于 的所有元素,它们在 中的颜色编号必须恰好每 个连续分为一组;
- 同一组内的元素颜色相同;
- 如果数值 出现的总次数无法被 整除,则无解,输出 ;
- 若有解,输出构造的染色数组 。
一句话总结: 数值为 的元素,必须每 个染成同一种颜色。
二、核心数学条件
对于每个 ,设 表示 在数组 中出现的次数,必须满足:
只要有一个 不满足,直接输出 。
三、算法流程(标程逻辑)
1. 统计位置
遍历数组 ,用
$$FRQ[i] = \{\text{所有满足 } a[pos]=i \text{ 的下标 } pos\} $$FRQ[i]存储所有数值等于 的下标位置。2. 合法性检查
遍历 ,检查:
不满足则标记无解。
3. 构造答案数组
- 按顺序给元素分组染色
- 每 个元素染成同一个颜色
- 染完一组,颜色编号
四、标程代码逐行详解
#include <iostream> #include <vector> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int T; cin >> T; // 测试用例数 while (T--) { int n; cin >> n; vector<int> a(n); for (int i = 0; i < n; ++i) { cin >> a[i]; // 输入数组 a } // FRQ[i]:存储所有数值 = i 的位置下标 vector<vector<int>> FRQ(n + 1); for (int i = 0; i < n; ++i) { FRQ[a[i]].push_back(i); } vector<int> b(n); // 答案数组 int cnt = 1; // 颜色编号,从 1 开始 bool ok = true; // 是否有解 // 遍历每个数值 i for (int i = 1; i <= n; ++i) { // 核心条件:出现次数必须能被 i 整除 if (FRQ[i].size() % i != 0) { ok = false; break; } int c = 0; int sz = FRQ[i].size(); // 每 i 个元素分一组,染同色 while (c < sz) { // 一组染 i 个元素 for (int v = 0; v < i; ++v) { b[FRQ[i][c]] = cnt; c++; } cnt++; // 下一组颜色+1 } } // 输出结果 if (!ok) { cout << -1 << '\n'; } else { for (int x : b) { cout << x << ' '; } cout << '\n'; } } return 0; }
五、复杂度分析
- 统计位置:
- 检查 + 构造:
- 总复杂度: 每组测试用例
- 完美支持
六、样例演示(直观理解)
示例:
- ,长度 , ✔️
每 1 个一组 → 颜色
[1,2] - ,长度 , ❌ 输出
七、总结
核心思想
- 统计位置:记录每个数值出现的位置
- 合法性判断:
- 分组染色:每 个元素染同一种颜色
- 输出构造结果
- 1
信息
- ID
- 6699
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 3
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者