P10382 题解
Register_int
·
·
题解
放 B 纯粹是怕 A 放分讨会被骂。
首先判掉一些显然有/无解的情况,比如初始就有环或者 x\le0 之类的。
本题关键在于一个交换操作。若一个空位填要填的数会导致成环,那么将其与其它空位交换即可消环。这个是好理解的,否则说明之前就存在环。
- 若仅有一个位置为 $0$,直接硬填判。
- 否则,先判 $x<2$ 显然无解:
- 若 $x\le n+1$,则存在用两个位置解决的方法:找一个 $-1$ 全填满,不合法的话换用第二个 $-1$ 填。可以证明是一定合法的。
- 否则,如果仅有两个空位,那么直接暴力枚举这两个空位是什么。
此时有三个空位。如果 $rt_n$ 是待定的,那么将 $a_{rt_n}$ 设为最大的 $k$ 使得 $rt_k$ 也待定即可。这样是为了贪心地取到最大的总和。
取完后,剩余的每个空位最多有 $n+1$ 的贡献。排掉不够的情况,不妨设还差的部分为 $x'$,算出 $t=\left\lfloor\frac{x'}{n+1}\right\rfloor$ 与 $y=x'\bmod(n+1)$。继续对 $y$ 讨论:
- $y=0$。可以暴力填前 $t$ 个。
- $y=1$。如果只剩两个空位,那么稍加分析可以发现只有 $t=y=1$ 的情况,那么直接硬放,若不满足再和 $rt_n$ 交换。否则,以一个空位作为调整的自由元,填掉剩下两个,不满足就和第三个空位交换。
- $y>1$。这是平凡的,用一个空位硬放后再找一个空位交换即可。
所以这些情况都是有解的,时间复杂度 $O(n)$。
```cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 10;
typedef long long ll;
int n, cnt, rt[MAXN]; ll x, a[MAXN];
bool l[MAXN]; vector<int> p, g[MAXN];
bool dfs(int u, int f) {
cnt++, rt[u] = f;
for (int v : g[u]) if (rt[v] || dfs(v, f)) return 1;
return 0;
}
void solve() {
int u, v, w, y, k; ll t;
for (int i = 1; i <= n; i++) {
if (!~a[i] && dfs(i, i)) { printf("Rick"); return; }
}
if (cnt < n) return puts("Rick"), void();
if (!x) { for (int i = 1; i <= n; i++) printf("%lld ", a[i]); return ; }
if (p.size() == 1) {
u = p[0];
a[u] += x;
if (a[u] < 1 || a[u] > n || rt[a[u]] == u) return puts("Rick"), void();
}
else if (p.size() > 1) {
if (x < 2) return puts("Rick"), void();
if (x <= n + 1) {
u = p[0], a[u] += x;
if (rt[a[u]] == u) v = p[1], swap(a[u], a[v]);
} else if (p.size() == 2) {
u = p[0], v = p[1];
for (a[u] = 1; a[u] <= n; a[u]++) {
a[v] = x - a[u] - 2;
if (a[v] > 0 && a[v] <= n && rt[a[u]] != u && rt[a[v]] != v
&& (rt[a[u]] != v || rt[a[v]] != u)) break;
}
if (a[u] > n) return puts("Rick"), void();
} else {
k = rt[n];
if (l[k]) {
for (a[k] = n - 1; a[k] && l[rt[a[k]]]; a[k]--);
if (!a[k]) a[k] = -1; x -= a[k] + 1;
p.erase(lower_bound(p.begin(), p.end(), k));
}
if (x > (ll)(n + 1) * p.size()) return puts("Rick"), void();
t = x / (n + 1), y = x % (n + 1);
for (int i = 0; i < t; i++) a[p[i]] = n;
if (y == 1) {
if (p.size() == 2 && l[k] && a[k] == -1) p.push_back(k);
if (p.size() == 2) {
x += a[k] + 1, x -= n + 1, a[k] = -1;
u = p[1], a[u] += x;
if (rt[a[u]] == u) swap(a[k], a[u]);
} else {
u = p[0], a[u] = 1;
v = p.back(), a[v] = n - 1;
w = p[1];
if (rt[a[u]] == u || rt[a[u]] == v && rt[a[v]] == u) swap(a[u], a[w]);
if (rt[a[v]] == v) swap(a[v], a[w]);
}
} else if (y > 1) {
u = p.back(), a[u] += y;
if (rt[a[u]] == u) v = p[p.size() - 2], swap(a[u], a[v]);
}
}
}
for (int i = 1; i <= n; i++) printf("%lld ", a[i]);
}
int main() {
scanf("%d%lld", &n, &x);
for (int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
if (!a[i]) p.emplace_back(i), a[i] = -1, l[i] = 1;
x -= a[i];
if (a[i] > 0) g[a[i]].emplace_back(i);
}
solve();
return 0;
}
```