P r o b l e m \mathrm{Problem} Problem
S o l u t i o n \mathrm{Solution} Solution
两个序列都是递增/递减序列时:
- 维护两个序列的末尾元素,每次放在较大/较小元素的后面。
两个序列一个递增,一个递减时:
- 设 f i f_i fi 表示第 i i i 个元素作为递增序列的末尾,递减序列末尾的最大值。
- 设 g i g_i gi 表示第 i i i 个元素作为递减序列的末尾,递增序列末尾的最小值。
接下来的转移以 f i f_i fi 为例:
- 当 a i > a i − 1 a_i>a_{i-1} ai>ai−1 时,第 i − 1 i-1 i−1 个元素能加入递增序列,则答案为 f i − 1 f_{i-1} fi−1。
- 当 a i > g i − 1 a_i>g_{i-1} ai>gi−1 时,第 i − 1 i-1 i−1 个元素能加入递减序列,则答案为 a i − 1 a_{i-1} ai−1。
同理我们可以得到 g g g 的转移方程。
方案根据DP结果倒推即可。
C o d e \mathrm{Code} Code
#include <bits/stdc++.h>
using namespace std;
const int N = 1000000;
int n, res, m1, m2;
int a[N], f[N], g[N], u[N], v[N], res1[N], res2[N];
int read(void)
{
int s = 0, w = 0; char c = getchar();
while (!isdigit(c)) w |= c == '-', c = getchar();
while (isdigit(c)) s = s*10+c-48, c = getchar();
return w ? -s : s;
}
void Dfs(int x,int type)
{
if (type == 1) {
if (u[x] == 1) Dfs(x-1, 1);
if (u[x] == 2) Dfs(x-1, 2);
}
if (type == 2) {
if (v[x] == 1) Dfs(x-1, 2);
if (v[x] == 2) Dfs(x-1, 1);
}
type == 1 ? res1[++ m1] = a[x] : res2[++ m2] = a[x];
return;
}
void print(void)
{
if (m1 == 0) res1[++ m1] = res2[m2 --];
if (m2 == 0) res2[++ m2] = res1[m1 --];
printf("%d %d\n", m1, m2);
for (int i=1;i<=m1;++i) printf("%d ", res1[i]); puts("");
for (int i=1;i<=m2;++i) printf("%d ", res2[i]); puts("");
return;
}
void work1(void)
{
m1 = m2 = 0;
int last1 = 0, last2 = 0;
for (int i=1;i<=n;++i)
{
if (a[i] < min(last1, last2)) return;
if (last1 >= last2) {
if (a[i] > last1) res1[++ m1] = a[i], last1 = a[i];
else res2[++ m2] = a[i], last2 = a[i];
}
else if (last1 < last2) {
if (a[i] > last2) res2[++ m2] = a[i], last2 = a[i];
else res1[++ m1] = a[i], last1 = a[i];
}
}
print();
exit(0);
}
void work2(void)
{
m1 = m2 = 0;
int last1 = 1e9, last2 = 1e9;
for (int i=1;i<=n;++i)
{
if (a[i] > max(last1, last2)) return;
if (last1 <= last2) {
if (a[i] < last1) res1[++ m1] = last1 = a[i];
else res2[++ m2] = last2 = a[i];
}
else if (last1 > last2) {
if (a[i] < last2) res2[++ m2] = last2 = a[i];
else res1[++ m1] = last1 = a[i];
}
}
print();
exit(0);
}
int main(void)
{
n = read();
for (int i=1;i<=n;++i) a[i] = read();
work1();
work2();
m1 = m2 = 0;
memset(f, 0, sizeof f);
memset(g, 30, sizeof g);
f[1] = 1e9, g[1] = 0;
for (int i=2;i<=n;++i)
{
if (a[i] > a[i-1] && f[i-1] > f[i]) f[i] = f[i-1], u[i] = 1;
if (a[i] > g[i-1] && a[i-1] > f[i]) f[i] = a[i-1], u[i] = 2;
if (a[i] < a[i-1] && g[i-1] < g[i]) g[i] = g[i-1], v[i] = 1;
if (a[i] < f[i-1] && a[i-1] < g[i]) g[i] = a[i-1], v[i] = 2;
}
if (f[0] != f[n]) Dfs(n, 1);
else if (g[0] != g[n]) Dfs(n, 2);
else return puts("Sorry Matsuri"), 0;
return 0;
}