1965. Pear Trees
Time limit: 1.0 second
Memory limit: 64 MB
Memory limit: 64 MB
题目链接
http://acm.timus.ru/problem.aspx?space=1&num=1965
题目叙述
给 一个 n 个数的排列
n < 1e5
问是否可以将这个排列拆成两个子序列
使得子序列严格递增 | 递减
比如
6
3 5 1 2 6 4
拆成
3 5 6
1 2 4
这样
8 7 1 6 4 3 5 2 拆成 ——
1 4 5
8 7 6 3 2
这样
Code
const int N = 1e5 + 9;
/**
0 for increase
1 for decrease
*/
int n;
int dp[N][4] , belong[N][4] , A[N] , pre[N][4];
/**
dp the minimum | maximum number when chose i to be the first sequence
belong which sequence will the number belong 0 | 1
pre how to transform
*/
bool update(int x , int y , int mask){
if (x == -1) return true;
return ((x > y) ^ mask);
}
void solve(){
for (int i = 0 ; i < n ; ++i) scanf("%d" , &A[i]);
FLC(dp , -1);
RST(belong);
dp[0][0] = dp[0][1] = 0;
dp[0][2] = dp[0][3] = INF;
for (int i = 0 ; i < n - 1; ++i)
for (int j = 0 ; j < 4 ; ++j) if (~dp[i][j]){
int first = j & 1;
int second = j >> 1;
if ((A[i + 1] > A[i]) ^ first){ // can update first sequence
if (update(dp[i + 1][j] , dp[i][j] , second)){
dp[i + 1][j] = dp[i][j];
belong[i + 1][j] = belong[i][j];
pre[i + 1][j] = j;
}
}
if ((A[i + 1] > dp[i][j]) ^ second){ // swap two sequence
int jj = first << 1 | second;
if (update(dp[i + 1][jj] , A[i] , first)){
dp[i + 1][jj] = A[i];
belong[i + 1][jj] = belong[i][j] ^ 1;
pre[i + 1][jj] = j;
}
}
}
VI ans[2]{};
for (int j = 0 ; j < 4 ; ++j) if (~dp[n - 1][j]){
// puts("Gosh");
for (int i = n - 1 ; i >= 0 ; --i){
ans[ belong[i][j] ].PB(A[i]);
j = pre[i][j];
}
reverse(ALL(ans[0]));
reverse(ALL(ans[1]));
if (!SZ(ans[1])){
ans[1].PB(ans[0].back());
ans[0].pop_back();
}
printf("%d %d\n" , SZ(ans[0]) , SZ(ans[1]));
for (int i = 0 ; i < SZ(ans[0]) ; ++i){
if (i) printf(" ");
printf("%d" , ans[0][i]);
}
puts("");
for (int i = 0 ; i < SZ(ans[1]) ; ++i){
if (i) printf(" ");
printf("%d" , ans[1][i]);
}
puts("");
return;
}
puts("Fail");
}
int main(){
while(cin >> n) solve();
}