15 收心赛3 T2 美食节 题解
美食节
原题:KOI 2022 食事计划
题面
有 \(n\) 个摊位,每个摊位提供一种类型的美食 \(a_1, a_2, a_3 ... a_n\) ,现需要你求出一个字典序最小的排列 \(p_1,p_2,p_3...p_n\) 使得 \(\forall 1 \le i < n, a_{p_i} \not= a_{p_{i + 1}}\)
如果无解,输出 -1
\(1 \le n \le 3 \times 10^5\)
\(1 \le a_i \le n\)
题解
这道题有点思维的,考虑什么时候无解?
当且仅当众数 \(> \lceil \frac n 2 \rceil\) 时,无解
那我们也可以扩展到已经填完 \(k\) 个数的情况,那么也就是剩下数的众数 \(> \lceil \frac {n - k} 2 \rceil\) 时无解
那么我们只需要从前向后遍历没有出现过的数,判断其是否可以填在这个位置,如果可以,那么就填,否则就判断下一个
考虑进行这个流程的过程中,其实两个不是众数的数对于是否无解的判断是等价的,所以我们可以直接去判断选众数还是最靠前的数即可
那么我们可以用两个 set 来维护,一个来按照出现次数排序,另一个按照出现位置排序,然后每次判断一下是否能填即可
时间复杂度 \(O(n \log n)\)
code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
using namespace std;
const int N = 3e5 + 10;
int n;
int a[N], now[N], nt[N], lst[N];
int cnt[N], la;
bool vis[N];
struct node {
int c, pos, val;
bool operator < (const node &o) const {
return c > o.c || (c == o.c && pos < o.pos);
}
};
set <node> s1; //按照出现次数排序,从大到小
set <pair <int, int> > s2; //按照出现位置排序,从小到大
void Do (int x) {
cout << now[x] << ' ';
la = x;
s1.erase ({cnt[x], now[x], x});
s2.erase ({now[x], x});
cnt[x] --;
if (!cnt[x]) return;
now[x] = nt[now[x]];
s1.insert ({cnt[x], now[x], x});
s2.insert ({now[x], x});
}
int main () {
freopen ("food.in", "r", stdin);
freopen ("food.out", "w", stdout);
cin >> n;
for (int i = 1; i <= n; i ++) {
cin >> a[i];
cnt[a[i]] ++;
}
for (int i = 1; i <= n; i ++) {
if (!lst[a[i]]) now[a[i]] = i;
else nt[lst[a[i]]] = i;
lst[a[i]] = i;
}
for (int i = 1; i <= n; i ++) {
if (cnt[i]) {
//s1中存 pos 的意义是如果有两个众数,那么我们应该优先选择出现位置靠前的那一个
s1.insert ({cnt[i], now[i], i});
s2.insert ({now[i], i});
}
}
//如果一开始就不合法,那就无解
if ((*s1.begin ()).c > (n + 1) / 2) {
cout << -1 << endl;
return 0;
}
//上一个位置的数,初始化为 -1
la = -1;
for (int i = 1; i <= n; i ++) {
node tmp = *s1.begin ();
if (tmp.c > (n - i + 1) / 2) {
//因为有解,而如果不这么填一定无解,所以一定要这么填
//因此不需要考虑是否和前一个位置相等的情况
Do (tmp.val);
} else {
auto it = s2.begin ();
//如果当前数可以填
if ((*it).second != la) {
Do ((*it).second);
} else {
it ++;
Do ((*it).second);
}
}
}
return 0;
}

浙公网安备 33010602011771号