Problem - 1620F - Codeforces
二分图本质上就是没有奇环,注意给定的是一个排列。
考虑什么时候会出现奇环,考虑如果 $(i, j), (j, k)$ 那么必然存在 $(i, k)$ 这样就去世了。
也就是如果存在 $(i, j)$ 那么 $\forall k \in [j + 1, n], a_k \ge a_j$。
我菜了。
既然结论已经想到这个份上了,直接考虑 $\tt Dp$。
我们注意结论:序列中不存在 $i < j < k, p_i > p_j > p_k$。
考虑进行填数设 $f(i, x, y)$ 表示填了 $i$ 个数,最大值为 $x$,已经填好的逆序对末尾的最大值为 $y$,能否没有奇环。
考虑优化状态,对于两个序列 $p_1, p_2$ 在相同的 $x$ 下选取较小的 $y$ 更加有潜力。
显然对于 $(i, y)$ 是固定的,$x$ 越小序列越容易合法。
考虑将状态变成 $f(i, x)$ 表示能取到的最小的 $y$。
如果不合法就是 $+\infty$。
转移方程,设 $z = \pm p_{i + 1}, f(i, x) = y(z \ge y)$。
$f(i + 1, x) = z, z < x$。
$f(i + 1, z) = y, z \ge x$。
发现其中至少有一个值是 $z$,所以状态是:
$f(i, 0/1, 0/1)$ 表示当前考虑到第 $i$ 个位置,当前数是 $+/-$,$x/y$ 是当前位置,值存的是剩下的那个数,复杂度是 $O(n)$ 的。
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 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
| #include <bits/stdc++.h> using namespace std; namespace Legendgod { namespace Read {
#ifdef Fread const int Siz = (1 << 21) + 5; char *iS, *iT, buf[Siz]; #define gc() ( iS == iT ? (iT = (iS = buf) + fread(buf, 1, Siz, stdin), iS == iT ? EOF : *iS ++) : *iS ++ ) #define getchar gc #endif template <typename T> void r1(T &x) { x = 0; char c(getchar()); int f(1); for(; !isdigit(c); c = getchar()) if(c == '-') f = -1; for(; isdigit(c); c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48); x *= f; } template <typename T, typename...Args> void r1(T &x, Args&...arg) { r1(x), r1(arg...); } #undef getchar }
using namespace Read;
const int maxn = 1e6 + 5; const int inf = 2e9; int n, m, p[maxn], f[maxn][2][2];
struct Node { int i, j, k; }pre[maxn][2][2]; #define rep(i, a, b) for (int i = (a); i <= (b); i++) #define per(i, a, b) for (int i = (a); i >= (b); i--) void Solve() { int i, j; r1(n); for(i = 1; i <= n; ++ i) r1(p[i]); for(i = 0; i <= n + 1; ++ i) for(j = 0; j < 2; ++ j) for(int k = 0; k < 2; ++ k) f[i][j][k] = inf; f[1][1][0] = f[1][0][0] = - inf; for(i = 1; i < n; ++ i) for(j = 0; j < 2; ++ j) for(int k = 0; k < 2; ++ k) { Node tmp = {i, j, k}; int x, y; if(!j && !k) x = p[i], y = f[i][j][k]; else if(!j && k) x = f[i][j][k], y = p[i]; else if(j && !k) x = - p[i], y = f[i][j][k]; else if(j && k) x = f[i][j][k], y = - p[i]; for(int z = 0; z < 2; ++ z) { int np = p[i + 1] * (z == 0 ? 1 : -1); if(np < y) continue; if(np < x) if(f[i + 1][z][1] > x) f[i + 1][z][1] = x, pre[i + 1][z][1] = tmp; if(np >= x) if(f[i + 1][z][0] > y) f[i + 1][z][0] = y, pre[i + 1][z][0] = tmp; } } for(i = 0; i < 2; ++ i) for(j = 0; j < 2; ++ j) if(f[n][i][j] < inf) { puts("YES"); int ni = i, nj = j, dep = n; static vector<int> vc; vc.clear(); while(dep > 0) { assert(f[dep][ni][nj] < inf); vc.push_back((ni == 0 ? 1 : -1) * p[dep]); Node tmp = pre[dep][ni][nj]; dep = tmp.i, ni = tmp.j, nj = tmp.k; } reverse(vc.begin(), vc.end()); for(const int& v: vc) printf("%d ", v); puts(""); return ; } puts("NO"); }
signed main() { int i, j, T; r1(T); while(T --) Solve(); return 0; }
}
signed main() { return Legendgod::main(), 0; }
|