1. 程式人生 > >位元組跳動冬令營網路賽 - B - Origami

位元組跳動冬令營網路賽 - B - Origami


題目連結<https://ac.nowcoder.com/acm/contest/296/B>


題意:

在一張長度為n的紙片上從左到右寫上1~n的數字。每次從左或從右反覆摺疊,使得最後只有一個單位的長度。這樣從上到下就會得到一個序列。給出一串序列問能否最後摺疊出來。


題解:

直接畫一下紙張摺疊最後形成的樣式,就可以發現題目可以翻譯成:給出左右兩串區間,要求每一串區間之間可以包含,相離,但不能相交。排序後利用棧維護即可。


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;
struct Node{
    int l,r;
    Node(int l=0,int r=0):l(l),r(r){}
    bool operator<(const Node a)const{
        if(l==a.l) return r<a.r;
        return l<a.l;
    }
}a[2][N];
int tp[2];
int t[N],T;
bool check(){
    sort(a[0]+1,a[0]+1+tp[0]);
    sort(a[1]+1,a[1]+1+tp[1]);
    stack<Node>st;
    for(int i=1;i<=tp[0];i++){
        while(!st.empty()){
            Node tt=st.top();
            if(a[0][i].r<tt.r) break;
            if(a[0][i].l<tt.r&&a[0][i].r>tt.r) return false;
            st.pop();
        }
        st.push(a[0][i]);
    }
    while(!st.empty()) st.pop();
    for(int i=1;i<=tp[1];i++){
        while(!st.empty()){
            Node tt=st.top();
            if(a[1][i].r<tt.r) break;
            if(a[1][i].l<tt.r&&a[1][i].r>tt.r) return false;
            st.pop();
        }
        st.push(a[1][i]);
    }
    return true;
}
int main()
{
    scanf("%d",&T);
    while(T--){
        int n,x;
        tp[0]=tp[1]=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&x);
            t[x]=i;
        }
        int sd=1;
        for(int i=2;i<=n;i++){
            int le=min(t[i],t[i-1]);
            int ri=max(t[i],t[i-1]);
            a[sd][++tp[sd]]=Node(le,ri);
            sd=sd^1;
        }
        if(check()) printf("Yes\n");
        else printf("No\n");
    }
}