# Codeforces 1615G. Maximum Adjacent Pairs (3300)

Posted by JustinK101 on Sun, 02 Jan 2022 18:47:24 +0100

Given the sequence \ (a \) with length \ (n \), the values of some positions in \ (a \) have been determined, and the values of others have not been determined. The number at these positions is \ (0 \), which needs to be replaced with the value of \ (1\sim n \).
Fill in all positions with \ (0 \) so that the number of \ (k(k\in [1,n]) \) meeting the following conditions is the largest, and construct any scheme.

• $$\exists i\in [1,n)$$，$$a_i=a_{i+1}=k$$.

$$2\le n\le 3\cdot 10^5,0\le a_i\le \min(n,600)$$.

In my lifetime, I came up with a question \ (\) on the field, but I didn't finish it \ () \).

$$\color{green}{\text{observation:}}$$
Considering that the valued part will divide the whole sequence into several segments, only the position of uncertain value adjacent to the valued position can match it.
Consider an interval \ ([l,r] \) with a length of \ (len \) and all \ (0 \), and discuss the parity of \ (len \).

• If \ (len \) is an odd number, it must be possible to match two pairs of \ (len-1 \), and the remaining one can match either \ (a {L-1} \) or \ (a {R + 1} \). According to the greedy strategy, this must be optimal. Assuming that both \ (a {L-1} \) and \ (a {R + 1} \) match, the maximum contribution is \ (2+\lfloor \frac{len-2}{2}\rfloor=\frac{len+1}{2} \), while the maximum contribution of the former is \ (1+\lfloor \frac{len-1}{2}\rfloor=\frac{len+1}{2} \). The maximum contribution is the same, but the latter two may not match with others. If the former can match, the latter must also match. Therefore, the contribution of the latter is always \ (\ ge \) the contribution of the former.
• If \ (len \) is even, there are only two cases. One is that both \ (a {L-1} \) and \ (a {R + 1} \) match, and the middle \ (len-2 \) match in pairs. The other is to match the middle \ (len \) directly regardless of the on both sides. According to the greedy strategy, these two can cover all situations. Although the former scheme has the greatest contribution, it may affect other matching, so both should be considered.

Then you can naturally think of using it General graph maximum matching Algorithm to solve.

Consider connecting edges.

• If \ (len \) is an odd number, connect \ (a {L-1} \) to a new point \ (v \), and \ (a {R + 1} \) to a new point \ (v \). Then \ (v \) can only match one of them.

• If \ (len \) is even, connect \ (a {L-1} \) to a new point \ (v 1 \), \ (a {R + 1} \) to a new point \ (V 2 \), and then connect \ (v 1 \) and \ (V 2 \). This just corresponds to the two cases discussed. If \ (a {L-1} \) and \ (v 1 \) are connected, and \ (a {R + 1} \) and \ (V 2 \) are connected, then both sides are matched; Otherwise, if \ (v_1 \) and \ (v_2 \) are connected, both sides do not match.

$$\color{blue}{\text{code}}$$

#include <bits/stdc++.h>
#define eb emplace_back
using namespace std;
const int N = 6e5 + 5, M = 12e5 + 5;
int n, a[N], id = 1, have[N], head[N], tot, ver[M], nxt[M];
int fa[N], vis[N], pre[N], match[N], dfn[N], timer; bool del[M], vs[N];
queue <int> q; vector <int> clr; vector < pair<int, int> > vec;
inline void add(int u, int v) {
ver[++tot] = v; nxt[tot] = head[u]; head[u] = tot;
ver[++tot] = u; nxt[tot] = head[v]; head[v] = tot;
}
inline int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
inline int lca(int u, int v) {
timer ++, u = find(u), v = find(v);
while(dfn[u] != timer) {
dfn[u] = timer;
u = find(pre[match[u]]);
if(v) u ^= v ^= u ^= v;
}
return u;
}
inline void blossom(int x, int y, int z) {
while(find(x) != z) {
pre[x] = y; y = match[x];
if(vis[y] == 2) vis[y] = 1, q.push(y), clr.eb(y);
if(x == find(x)) fa[x] = z;
if(y == find(y)) fa[y] = z;
x = pre[y];
}
}
inline bool bfs(int s) {
for (auto x : clr) vis[x] = pre[x] = 0, fa[x] = x; clr.clear();
while(!q.empty()) q.pop();
q.push(s); vis[s] = 1; clr.eb(s);
while(!q.empty()) {
int u = q.front(); q.pop();
for(int i = head[u]; i; i = nxt[i]) {
int v = ver[i];
if(vis[v] == 2 || find(u) == find(v)) continue;
if(vis[v] == 0) {
vis[v] = 2; pre[v] = u; clr.eb(v);
if(!match[v]) {
for(int x = v, lst; x; x = lst) {
lst = match[pre[x]];
match[x] = pre[x];
match[pre[x]] = x;
}
return 1;
}
vis[match[v]] = 1;
q.push(match[v]);
clr.eb(match[v]);
}
else {
int w = lca(u, v);
blossom(u, v, w); blossom(v, u, w);
clr.eb(v), clr.eb(w);
}
}
}
return 0;
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n + n; ++ i) fa[i] = i;
for (int i = 1; i <= n; ++ i) scanf("%d", a + i), have[a[i]] = 1;
for (int i = 1; i < n; ++ i) if (a[i] == a[i - 1] && a[i]) vs[a[i]] = 1;
for (int i = 1, j; i <= n; i = j + 1) {
j = i; if (a[i]) continue;
while (!a[j] && j <= n) ++ j;
vec.emplace_back(i, j);
if ((j - i) & 1) {
if (i > 1 && !vs[a[i - 1]]) add(a[i - 1], n + i);
if (j <= n && !vs[a[j]]) add(a[j], n + i);
} else {
if (i > 1 && !vs[a[i - 1]]) add(a[i - 1], n + i);
if (j <= n && !vs[a[j]]) add(a[j], n + j - 1);
add(n + i, n + j - 1);
}
}
for (int i = 1; i <= n + n; ++ i) if (!match[i]) bfs(i);
for (auto p : vec) {
int l = p.first, r = p.second;
if ((r - l) & 1) {
if (l > 1 && match[n + l] == a[l - 1]) {
a[l] = a[l - 1];
for (int i = l + 1; i + 1 < r; i += 2) {
while (have[id]) ++ id;
a[i] = a[i + 1] = id ++;
}
} else {
for (int i = l; i + 1 < r; i += 2) {
while (have[id]) ++ id;
a[i] = a[i + 1] = id ++;
}
a[r - 1] = a[r];
}
} else {
if (match[n + l] == n + r - 1) {
for (int i = l; i + 1 < r; i += 2) {
while (have[id]) ++ id;
a[i] = a[i + 1] = id ++;
}
} else {
a[l] = a[l - 1], a[r - 1] = a[r];
for (int i = l + 1; i + 1 < r; i += 2) {
while (have[id]) ++ id;
a[i] = a[i + 1] = id ++;
}
}
}
}
for (int i = 1; i <= n; ++ i) printf("%d ", a[i] ? a[i] : 1);
return 0;
}