[ARC 102F]Revenge of BBuBBBlesort!

Atcoder ARC 102F

F:Revenge of BBuBBBlesort!

题意:

给你一个长度为\(n\)的排列\(A\),可以交换\((a_i,a_{i+1},a_{i+2})\)当且仅当\(a_i>a_{i-1}>a_{i-2}\),问\(A\)是否能经过一系列交换最后有序
\(1 \le n \le 300000\)

题解:

emmmm有大佬看错了题,于是就变成了毒瘤题
真是道神仙题。。看了题解才会,证明容易构造困难啊。
先构造\(B_i=[A_i=i]\)
有这个结论
如果B中有3个连续的0,则没有构造方案\((1)\)
定义一个序列是合法的,当其01交错且两端是0,特殊地,单独的0,1也是合法的
我们先极大化每个位置所在合法序列的长度,然后如果对于所有合法序列同时满足以下条件,则存在方案,对于一个\([l,r]\)
1.其中元素的值域也在\([l,r]\),要不然换不出去的
2.对于目标在左边的元素,对于任意的\(i < j\)满足\(a_i < a_j\) \((2)\)
3.对于目标在右边的元素,对于任意的\(i < j\)满足\(a_i < a_j\) \((2)\)
以下是口胡的证明:
\((1)\):
记这三个的位置是\((i-1,i,i+1)\)如果以\(i\)为中心转了,那么\(i\)就动不了了,\(i-1\),\(i+1\)同理
\((2)\):
这两个东西原理一样,一起证掉,按目标在左边的考虑
如果有一个 \(i <j\),但\(a_i > a_j\),那么\(a_j\)一定要跨过\(a_i\),但这显然不太可能。。

过程:

1A

代码:

#define GG {puts("No"); return 0;}
const int N=300010;
int n;
int a[N],b[N];
inline bool Check(int l,int r) {
    int lbd=0,rbd=0;
    for(int i=l;i<=r;i++) {
        if(b[i]<i) {
            // printf("%d\n",i);
            if(lbd>b[i] || (b[i]<l || b[i]>r)) return false;
            lbd=b[i];
        } else if(b[i]>i) {
            if(rbd>b[i] || (b[i]<l || b[i]>r)) return false;
            rbd=b[i];
        }
    }
    return true;
}
signed main() {
    read(n);
    for(int i=1;i<=n;i++)
        read(b[i]),a[i]=(b[i]==i);
    for(int i=2;i<n;i++) if(!a[i-1] && !a[i] && !a[i+1]) GG
    for(int i=1;i<=n;i++) {
        if(a[i]==0) {
            int now=1;
            int l=i,r=i;
            while((a[r]^now) && r<=n) ++r,now^=1;
            --r;
            if(!Check(l,r)) GG
            i=r;
        }
    }
    puts("Yes");
    return 0;
}

用时:20min

转载于:https://www.cnblogs.com/functionendless/p/9574865.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值