题解:CF1620F Bipartite Array
题意:很简单了,不再赘述。
做法:
这个奇环太难描述了,看起来很困难,不过手玩之后很明显发现等同于没有一个长度 \(\ge 3\) 的 \(LDS\)。
那么我们很显然可以设计一个 \(O(n^3)\) 的 dp,\(dp_{i,j,k}\) 代表前 \(i\) 个数,最大值为 \(j\),作为 \(LDS\) 的第二个数的最大值为 \(k\),是否可行,直接枚举转移即可。
然后我们就要大力优化这个 dp。首先我们注意到这个 dp 是个 0/1 的 dp 太浪费了,同时我们注意到,当我们的 \(j\) 一定时,我们的 \(k\) 一定是越小越好的,因为这样就更难形成一个 3 长度的 \(LDS\),同理也可以得到 \(k\) 一定时,\(j\) 越小越好,所以我们可以随便压掉一位,将这一位计入答案里即可,这里我们状态中记录的是最大值,复杂度 \(O(n^2)\)。
然后我们继续观察,我们发现这两维中一定有一维是由 \(p_{i-1}\) 贡献的!所以我们考虑记 \(f_{i,0/1,0/1}\) 代表在上面那个 \(O(n^2)\) dp 中是在状态那一维中还是在值中,如果在值中我们就记录的是最大值的最小值,去跑 dp 即可。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
int dp[maxn][2][2], n, p[maxn];
struct node {
int i, x, y;
} pre[maxn][2][2];
void solve() {
cin >> n;
for (int i = 1; i <= n; i++)
cin >> p[i];
for (int i = 0; i <= n; i++)
dp[i][0][0] = dp[i][0][1] = dp[i][1][0] = dp[i][1][1] = 2e9;
dp[1][0][0] = dp[1][1][0] = -2e9;
for (int i = 1; i < n; i++) {
for (int x = 0; x <= 1; x++) {
for (int y = 0; y <= 1; y++) {
int mx, ed;
if(y == 0)
mx = p[i] * (x == 0 ? 1 : -1), ed = dp[i][x][y];
if(y == 1)
mx = dp[i][x][y], ed = p[i] * (x == 0 ? 1 : -1);
// cout << i << " " << mx << " " << ed << endl;
for (int t = 0; t <= 1; t++) {
int v = p[i + 1] * (t == 0 ? 1 : -1);
if(ed > v)
continue;
if(mx > v) {
if(dp[i + 1][t][1] > mx)
dp[i + 1][t][1] = mx, pre[i + 1][t][1] = node{i, x, y};
}
if(mx <= v) {
// cout << mx << " " << v << endl;
if(dp[i + 1][t][0] > ed)
dp[i + 1][t][0] = ed, pre[i + 1][t][0] = node{i, x, y};
}
}
}
}
}
node p1 = {n, 0, 0};
for (int x = 0; x <= 1; x++)
for (int y = 0; y <= 1; y++)
if(dp[n][x][y] != dp[0][0][0])
p1 = node{n, x, y};
if(dp[p1.i][p1.x][p1.y] == dp[0][0][0]) {
cout << "NO" << endl;
return ;
}
vector<int> ans;
while(p1.i) {
ans.push_back((p1.x == 0 ? 1 : -1) * p[p1.i]);
p1 = pre[p1.i][p1.x][p1.y];
}
reverse(ans.begin(), ans.end());
cout << "YES" << endl;
for (int i = 0; i < n; i++)
cout << ans[i] << " ";
cout << endl;
}
int main() {
int T; cin >> T;
while(T--)
solve();
return 0;
}

浙公网安备 33010602011771号