【UR #12】实验室外的攻防战

UOJ小清新题表

题目内容

依然没有粘题面主要是UOJ的题面都太长了qwq

UOJ链接

一句话题意:给出两个序列 \(A\)\(B\),对于 \(A\) 进行若干次操作,每次给出一个 \(i\),若 \(A_i>A_{i+1}\) 则可交换。问能否通过若干次操作后把 \(A\) 序列转化为 \(B\) 序列。

数据范围

子任务 分值 限制与约定
1 24 \(n\leq 8\)
2 32 \(n\leq 1000\)
3 44 \(n\leq 100000\)

思路

好像是一道三维偏序题。可以先想想冒泡排序的运行方式。

首先有一个显然的性质。若遍历到两个数 \(i\)\(j\)\(i<j\),若在 \(A\) 序列中 \(i\)\(j\) 之前,在 \(B\) 序列中 \(i\)\(j\) 之后,那么永远都无法将其转化为符合条件的位置。当我们遍历到这样的情况的时候,直接输出NO就完了。

形式化的说,不满足条件的限制就是:存在对于 \(i<j\) 的两个数,使得 \(a[i]<a[j]\)\(b[i]>b[j]\)。其中 \(a[i]\) 表示 \(i\)\(A\) 序列的位置,\(b[i]\) 表示 \(i\)\(B\) 序列中的位置,这个直接在读入的时候就已经处理好了。

此题判断其存在性即可。对于 \(i<j\),可以从小到大枚举每一个 \(j\),找出所有的 \(a[i]<a[j]\)\(b[i]\) 的最大值,判断其是否大于 \(b[j]\),若不符合,加入 \(j\) 即可,否则直接输出NO

若最终都无法找到,则答案为YES

然后剩下的就是随便找一个数据结构维护一下最大值就行了,这里采用的是树状数组。

可能有点混乱,看代码应该能懂

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int n;
int a[maxn],b[maxn],tree[maxn];

inline int read(){
    int x=0,fopt=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')fopt=-1;
    for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-48;
    return x*fopt;
}

inline int lowbit(int x){
    return x&-x;
}

inline void modify(int x,int b){
    while(x<=n){
        tree[x]=max(tree[x],b);
        x+=lowbit(x);
    }
}

inline int query(int x){
    int ans=-1;
    while(x){
        ans=max(ans,tree[x]);
        x-=lowbit(x);
    }
    return ans;
}

int main(){
    n=read();
    for(int i=1;i<=n;i++)
        a[read()]=i;
    for(int i=1;i<=n;i++)
        b[read()]=i;
    for(int i=1;i<=n;i++)
        if(query(a[i])>b[i])return puts("NO"),0;//询问所有下标小于等于i的最大值
        else modify(a[i],b[i]);//交换操作,直接一步到胃
    puts("YES");
    return 0;
}
posted @ 2020-08-17 19:53  Midoria7  阅读(92)  评论(2编辑  收藏  举报