CF1620F Bipartite Array
不难发现本题的图在随机的情况下会很稠密,并且很容易出现奇环。仔细想想,会发现奇环出现的充要条件应该并不复杂。
考察最小的情况,也即长度为 \(3\) 的奇环,出现这样的环意味着有 \(i<j<k\) \(p_i>p_j>p_k\)。 仔细想一想,任何一个奇环都会包含这样三个位置 \(i,j,k\) 那么问题就更加简单化了,至此问题被转换为,是否能通过对于每个位置取反的操作使原数列不能出现满足 \(i<j<k\) , \(p_i>p_j>p_k\) 的这样 \((i,j,k)\) 三元组。
先做一个 naive 的 \(DP\), 设 \(f_{i,x,y}\) 表示序列最大数为 \(x\),所有逆序对末尾数最大为 \(y\),能否存在长度为 \(3\) 的奇环。
转移 \(O(1)\) 状态 \(O(n^3)\) 考虑优化状态。
不难发现,将 \(y\) 一维去掉只记 \(f_{i,x}\) 表示构造完前 \(i\) 个数后形成的最大数为 \(x\) 的序列,逆序对末尾的最小数为 \(f_{i,x}\) 即可。因为对于相同的 \(x\)。 \(y\) 越小显然越好。
看上去似乎这个无法再进一步优化状态,我们尝试写下状态转移方程:
设 \(z = \pm p_{i+1}, f_{i,x}=y (z\geq y)\) (显然我们只能使得 \(z \geq y\)) 则我们有:
- \(z<x \Rightarrow f_{i+1,x}=z\)
- \(z\geq x \Rightarrow f_{i+1,z}=y\)
那么我们只需要记 \(f_{i,j,k}\) 代表前 \(i\) 位, 第 \(i\) 位, 第 \(i\) 位填的是 正/负 \((j = 0/1)\),其中 \(x\) \(or\) \(y = \pm p_{i}\) \((k = 0/1)\)。
Tips:
限制比较苛刻的构造题,可以考虑是否所有小情况满足就能合法。
\(DP\) 题优化状态时需要考察转移方程。
#include<bits/stdc++.h>
#define RG register
#define LL long long
#define U(x, y, z) for(RG int x = y; x <= z; ++x)
#define D(x, y, z) for(RG int x = y; x >= z; --x)
#define update(x, y) (x = x + y >= mod ? x + y - mod : x + y)
using namespace std;
void read(){}
template<typename _Tp, typename... _Tps>
void read(_Tp &x, _Tps &...Ar) {
x = 0; char ch = getchar(); bool flg = 0;
for (; !isdigit(ch); ch = getchar()) flg |= (ch == '-');
for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
if (flg) x = -x;
read(Ar...);
}
inline char Getchar(){ char ch; for (ch = getchar(); !isalpha(ch); ch = getchar()); return ch;}
template <typename T> inline void write(T n){ char ch[60]; bool f = 1; int cnt = 0; if (n < 0) f = 0, n = -n; do{ch[++cnt] = char(n % 10 + 48); n /= 10; }while(n); if (f == 0) putchar('-'); for (; cnt; cnt--) putchar(ch[cnt]);}
template <typename T> inline void writeln(T n){write(n); putchar('\n');}
template <typename T> inline void writesp(T n){write(n); putchar(' ');}
template <typename T> inline void chkmin(T &x, T y){x = x < y ? x : y;}
template <typename T> inline void chkmax(T &x, T y){x = x > y ? x : y;}
template <typename T> inline T Min(T x, T y){return x < y ? x : y;}
template <typename T> inline T Max(T x, T y){return x > y ? x : y;}
inline void readstr(string &s) { s = ""; static char c = getchar(); while (isspace(c)) c = getchar(); while (!isspace(c)) s = s + c, c = getchar();}
inline void FO(string s){freopen((s + ".in").c_str(), "r", stdin); freopen((s + ".out").c_str(), "w", stdout);}
const int N = 1e6 + 10;
#define ep emplace_back
int n, p[N], f[N][2][2];
vector<int> ans;
#define inf 2e9
struct node {
int i, j, k;
} pre[N][2][2];
inline void solve() {
read(n);
U(i, 1, n) read(p[i]);
U(i, 0, n + 1) U(j, 0, 1) U(k, 0, 1) f[i][j][k] = inf;
f[1][0][0] = f[1][1][0] = -inf;
U(i, 1, n - 1) U(j, 0, 1) U(k, 0, 1) {
int x, y, tmp = f[i][j][k];
if (!j && !k) x = -p[i], y = tmp;
if (!j && k) x = tmp, y = -p[i];
if (j && !k) x = p[i], y = tmp;
if (j && k) x = tmp, y = p[i];
node cur = (node) {i, j, k};
U(t, 0, 1) {
int z = (t ? 1 : -1) * p[i + 1];
if (z < y) continue ;
if (z < x && f[i + 1][t][1] > x)
f[i + 1][t][1] = x, pre[i + 1][t][1] = cur;
if (z >= x && f[i + 1][t][0] > y)
f[i + 1][t][0] = y, pre[i + 1][t][0] = cur;
}
}
U(bj, 0, 1) U(bk, 0, 1) {
int i = n, j = bj, k = bk;
if (f[i][j][k] != inf) {
ans.clear();
puts("YES");
while (i) {
ans.emplace_back(j ? p[i] : -p[i]);
node cur = pre[i][j][k];
i = cur.i, j = cur.j, k = cur.k;
}
reverse(ans.begin(), ans.end());
for (auto u: ans) writesp(u);
putchar('\n');
return ;
}
}
puts("NO");
}
int main(){
//FO("");
int T;
read(T);
while (T--) solve();
return 0;
}