[Open Ural FU Personal Contest 2013]E.Pear Trees wuyiqi's method

1965. Pear Trees

Time limit: 1.0 second
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();
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值