思路:
容易得出最多不超过长度为二的下降子序列
所以序列可以表示为两个上升子序列
设dpi,0/1表示以i为开头的子序列,另外一个子序列的开头最大是多少。
然后我们就可以dp,从-a[i],a[i],dp[i][1],dp[i][0]转移。
然后根据dp贪心构造
c o d e code code
#include<iostream>
#include<cstdio>
using namespace std;
const int MAXN = 1e6 + 10;
int t;
int dp[MAXN][2], a[MAXN];
int tmp[4][2];
int main() {
scanf("%d", &t);
while(t --) {
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i ++)
scanf("%d", &a[i]), dp[i][0] = dp[i][1] = -1e9;
dp[n][0] = dp[n][1] = 1e9;
for(int i = n; i > 1; i --) {
tmp[0][0] = tmp[2][1] = -a[i];
tmp[0][1] = tmp[2][0] = dp[i][0];
tmp[1][0] = tmp[3][1] = a[i];
tmp[1][1] = tmp[3][0] = dp[i][1];
for(int j = 0; j < 2; j ++) {
int w = a[i - 1];
if(j == 0) w = -w;
for(int k = 0; k < 4; k ++)
if(w < tmp[k][0])
dp[i - 1][j] = max(dp[i - 1][j], tmp[k][1]);
}
}
if(dp[1][0] == dp[1][1] && dp[1][0] == -1e9) {
printf("NO\n");
continue;
}
printf("YES\n");
int l1 = -1e9, l2 = -1e9;
for(int i = 1; i <= n; i ++) {
if(-a[i] > l1) {
l1 = -a[i];
printf("%d ", -a[i]);
}
else if(-a[i] > l2 && -a[i] < dp[i][0]) {
l2 = -a[i];
printf("%d ", -a[i]);
}
else {
l1 = a[i];
printf("%d ", a[i]);
}
if(l1 < l2) swap(l1, l2);
}
printf("\n");
}
return 0;
}