zoukankan      html  css  js  c++  java
  • [atARC102F]Revenge of BBuBBBlesort

    定义以$i$为中心(交换$p_{i-1}$和$p_{i+1}$)的操作为操作$i$

    结论1:若执行过操作$i$,则之后任意时刻都无法执行操作$i-1$或操作$i+1$

    当执行操作$i$后,必然有$p_{i-1}<p_{i}$,然后不妨假设下一次与$i$相邻的操作为$i-1$($i+1$类似)

    操作$i-1$的条件为$p_{i-2}>p_{i-1}>p_{i}$,即要增大$p_{i-1}$或减小$p_{i}$,可以执行操作$i-2$或操作$i+1$,后者根据假设不成立

    对于操作$i-2$,其执行完后必然有$p_{i-2}<p_{i-1}$,类似的我们又要求执行操作$i-3$来增大$p_{i-2}$……以此类推,当需要执行操作1来增大$p_{2}$即不合法

    推论1:执行操作$i$必须有$p_{i}=i$

    根据结论1,执行操作$i$后无法再执行操作$i-1$或$i+1$,即无法再修改$p_{i}$,而最终要求$p_{i}=i$

    推论2:若初始$p_{i} e i$,则一定不会执行操作$i$;若$p_{i}=i$,则一定不会执行操作$i-1$或操作$i+1$

    根据推论1,执行操作$i$需要$p_{i}=i$,而修改$p_{i}$必然执行了操作$i-1$或$i+1$,则不能执行操作$i$

    根据推论1,执行操作$i-1$($i+1$类似)要求$p_{i-1}=i-1<p_{i}$,不成立

    考虑将整个序列划分为独立的若干段,即要求每一段的端点都不能操作,这等价于将其在$i$和$i+1$之间断开则要求$i$和$i+1$都无法操作,不妨将所有这些位置都断开,考虑每一段的形式:

    1.那么每一段必然不会出现相邻两数$i$和$i+1$使得$[p_{i}=i]=[p_{i+1}=i+1]$,否则必然可以断开

    2.如果端点满足$p_{i}=i$(以下假设为左端点),则$i$无法操作,同时$i+1$也无法操作,可以断开(除非$i+1$不在该段中,即仅一个$p_{i}=i$)

    更形象的,记$s_{i}=[p_{i}=i]$(一个01串),那么最终每一段的$s$分为两种:1.仅一个'1';2.以'0'为开头结尾的'01010...10'

    对于第1种段直接删去即可,对于第2种继续分析

    可以看作对$p_{l},p_{l+2},...,p_{r}$这一段排序,而要交换$p_{i}$和$p_{i+2}$,则要求$p_{i}>i+1>p_{i+2}$

    由于$p_{i}equiv i(mod 2)$,因此$p_{i}>i+1$也即$p_{i}>i$,类似的后者也即$i+2>p_{i+2}$

    对于初始$p_{i}>i$的位置,其一定只能向后交换,且若交换至$p_{i}=i$,根据推论2,一定不会再改变($p_{i}<i$的位置类似)

    其限制且仅限制(若两点都满足交换方向一定可行)了每一个数的交换方向,那么合法即要求:

    1.如果是区间$[l,r]$,$forall lle ile r,lle p_{i}le r$

    2.对于$p_{i}>i$的位置,其之前不存在比其大的数;对于$p_{i}<i$的位置,其之后不存在比其小的数

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 300005
     4 int n,a[N],p[N];
     5 int main(){
     6     scanf("%d",&n);
     7     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
     8     for(int i=1;i<=n;i++)p[i]=1;
     9     for(int i=1;i<=n;i++)
    10         if (a[i]!=i)p[i]=0;
    11         else p[i-1]=p[i+1]=0;
    12     for(int i=1,j=1;i<=n;i=++j){
    13         for(;j<n;j++)
    14             if ((!p[j])&&(!p[j+1]))break;
    15         if ((i==j)&&(p[i]==i))continue;
    16         for(int k=i;k<=j;k++)
    17             if ((a[k]<i)||(j<a[k])){
    18                 printf("No");
    19                 return 0;
    20             }
    21         int mx=0,mn=n;
    22         for(int k=i;k<=j;k++){
    23             if ((a[k]>k)&&(a[k]<mx)){
    24                 printf("No");
    25                 return 0;
    26             }
    27             mx=max(mx,a[k]);
    28         }
    29         for(int k=j;k>=i;k--){
    30             if ((a[k]<k)&&(a[k]>mn)){
    31                 printf("No");
    32                 return 0;
    33             }
    34             mn=min(mn,a[k]);
    35         }
    36     }
    37     printf("Yes");
    38 }
    View Code
  • 相关阅读:
    进程间通信:命名管道FIFO(2)
    进程间通信:管道(1)
    POSIX线程学习
    进程与信号学习
    堆栈的区别与联系
    浅读《构建之法:现代软件工程》有感
    CSS学习成长记
    jquery学习成长记(一)
    html学习成长记
    Razor视图
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/13957452.html
Copyright © 2011-2022 走看看