传送门

 
 
策爷的论文题啊……题解在这儿

我只想知道为什么这题的弱化版会出现在我们今天的%你赛里……

题意:给你一堆操作$(l,r)$,表示将区间$(l,r)$按升序排序。以及$q$个询问,每次询问一个数列能否在上述操作之后变为有序

首先,我们要知道如果只有一次询问的话,我们要怎么乱搞。首先,排序的交换次数下界等于逆序对个数,我们只要对于$(l,r)$中的每一个满足$a[i]>a[i+1]$的元素,交换$i$和$i+1$,那么交换次数就能刚好为逆序对个数,即$O(n^2)$

所以对于每一个操作,我们都可以在区间中消逆序对。考虑怎么快速找到所有的逆序对。我们可以把所有的满足$a[i]>a[i+1]$的$i$给丢进set里,那么每次只要二分找到在这个区间中的$i$,然后交换,删掉原来的逆序对并加入新的逆序对就可以了。时间复杂度为$O((n^2+m)logn)$,优于$O(nmlogn)$代码如下

  1. void SORT(rint l,rint r){
  2. rint i;
  3. while((i=*s.upper_bound(l-))>=l&&i<r){
  4. s.erase(i),swap(a[i],a[i+]);
  5. if(a[i]<a[i+]&&a[i+]>a[i+])s.insert(i+);
  6. if(a[i-]>a[i]&&a[i-]<a[i+])s.insert(i-);
  7. }
  8. }

然后就是神仙操作了……我们先考虑什么样的初始序列可以被排好序,我们从$01$序列开始考虑,如果一个$111000$的初始序列可以通过一堆操作之后变得有序,那么$101010$的序列必然也可以(感性理解一下发现很显然),那么我们就说$101010$比$111000$更优。总的来说,一个序列中$0$越靠左,$1$越靠右,那么这个序列越接近升序,这个序列就越优。设$pos(a,i)$表示数列$a$中第$i$个$1$所在的位置。对于两个数列来说,如果$a$比$b$更优,当且仅当对于所有$i$都有$pos(a,i)\geq pos(b,i)$。

那么我们只要能得到最差的能被排好序的初始序列,那么所有比它更优的一定能够排好序。

于是我们可以设原数列为$A$,且是一个$n$的排列(如果不是的话我们可以把它给离散,并把元素相同的按下表排列,可以发现这样并不会影响结果)。考虑如何从$01$序列拓展到这个$n$排列,对于$A$和某个数值$k$,定义$01$序列$B_k$,$B_k[i]$为$1$当且仅当$A[i]\geq k$。

于是我们发现,如果对于所有的$k=2,3,...n$,$B_k$都能在这些操作下变得有序,那么原排列也可以

直接做太慢了,我们设原排列为$1,2,...,n$,然后对于$m$次操作,我们按$i$从$m$到$1$的顺序每一次都用上面的方法使区间$[l_i,r_i]$降序排序(变为最差的)

最后得到的序列中,小于$k$的位置用$0$表示,其他位置用$1$表示,得到的$01$序列为$C_k$,且$C_k$只要更改一个位置上的值就能变为$C_{k-1}$

于是只要所有的$B_k$都比对应的$C_k$优秀,那么原排列就能在若干次操作后变为有序,即$B_k$的任意一个前缀和都不能大于$C_k$的前缀和

如果我们把$B_k$中的$1$取相反数,并把两个前缀和相加,那么只要每一个前缀和都大于等于$0$即可。设$posb[i]$表示元素$i$在$B_k$中的位置,$posc[i]$表示元素$i$在$C_k$中的位置。当求完$k=i$要求$k=i+1$的时候,$posb[i+1]$处的元素变为$-1$,那么它以及后面所有数的前缀和都会减一,$posc[i]$的变化同理。于是我们只要维护好前缀和,并判断最小的前缀和是否小于$0$即可。区间赋值和区间取$min$用线段树就可以了

  1. //minamoto
  2. #include<bits/stdc++.h>
  3. #define rint register int
  4. #define min(x,y) ((x)<(y)?(x):(y))
  5. #define ls (p<<1)
  6. #define rs (p<<1|1)
  7. #define ppd(p,v) (mn[p]+=(v),tag[p]+=(v))
  8. #define mem(a) (memset(a,0,sizeof(a)))
  9. using namespace std;
  10. #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
  11. char buf[<<],*p1=buf,*p2=buf;
  12. int read(){
  13. int res,f=;char ch;
  14. while((ch=getc())>''||ch<'')(ch=='-')&&(f=-);
  15. for(res=ch-'';(ch=getc())>=''&&ch<='';res=res*+ch-'');
  16. return res;
  17. }
  18. const int N=,M=1e6+;
  19. int n,m,q,c[N],posc[N],b[N],posb[N],mn[N<<],tag[N<<];
  20. struct ques{int l,r;}p[M];set<int>s;
  21. struct node{
  22. int val,id;
  23. inline bool operator <(const node &b)const{return val==b.val?id<b.id:val<b.val;}
  24. }f[N];
  25. void SORT(rint l,rint r){
  26. rint i;
  27. while((i=*s.upper_bound(l-))>=l&&i<r){
  28. s.erase(i),swap(c[i],c[i+]);
  29. if(c[i+]<c[i+]&&c[i]>c[i+])s.insert(i+);
  30. if(c[i-]<c[i]&&c[i-]>c[i+])s.insert(i-);
  31. }
  32. }
  33. inline void pd(int p){if(tag[p])ppd(ls,tag[p]),ppd(rs,tag[p]),tag[p]=;}
  34. void update(int p,int l,int r,int ql,int qr,int v){
  35. if(ql<=l&&qr>=r)return (void)(ppd(p,v));
  36. int mid=(l+r)>>;pd(p);
  37. if(ql<=mid)update(ls,l,mid,ql,qr,v);
  38. if(qr>mid)update(rs,mid+,r,ql,qr,v);
  39. mn[p]=min(mn[ls],mn[rs]);
  40. }
  41. int main(){
  42. // freopen("testdata.in","r",stdin);
  43. n=read(),m=read(),q=read();
  44. for(int i=;i<=m;p[i].l=read(),p[i].r=read(),++i);
  45. for(int i=;i<=n;c[i]=i,++i);
  46. for(int i=;i<n;s.insert(i),++i);
  47. for(int i=m;i;SORT(p[i].l,p[i].r),--i);
  48. for(int i=;i<=n;posc[c[i]]=i,++i);
  49. while(q--){
  50. for(int i=;i<=n;f[i].val=read(),f[i].id=i,++i);
  51. sort(f+,f++n);
  52. for(int i=;i<=n;b[f[i].id]=i,++i);
  53. for(int i=;i<=n;posb[b[i]]=i,++i);
  54. mem(mn),mem(tag);
  55. bool flag=;
  56. for(int i=;i<=n;++i){
  57. update(,,n,posb[i-],n,);
  58. update(,,n,posc[i-],n,-);
  59. if(mn[]<){flag=;break;}
  60. }
  61. puts(flag?"AC":"WA");
  62. }
  63. return ;
  64. }

bzoj4534: 基础排序算法练习题的更多相关文章

  1. Java面试宝典系列之基础排序算法

    本文就是介绍一些常见的排序算法.排序是一个非常常见的应用场景,很多时候,我们需要根据自己需要排序的数据类型,来自定义排序算法,但是,在这里,我们只介绍这些基础排序算法,包括:插入排序.选择排序.冒泡排 ...

  2. php四种基础排序算法的运行时间比较

    /** * php四种基础排序算法的运行时间比较 * @authors Jesse (jesse152@163.com) * @date 2016-08-11 07:12:14 */ //冒泡排序法 ...

  3. Java基础系列--基础排序算法

    原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/9082138.html 一.概述 基础排序算法包括:桶排序.冒泡排序.选择排序.插入排序等 ...

  4. 6种基础排序算法java源码+图文解析[面试宝典]

    一.概述 作为一个合格的程序员,算法是必备技能,特此总结6大基础算法.java版强烈推荐<算法第四版>非常适合入手,所有算法网上可以找到源码下载. PS:本文讲解算法分三步:1.思想2.图 ...

  5. php四种基础排序算法的运行时间比较!

    /** * php四种基础排序算法的运行时间比较 * @authors Jesse (jesse152@163.com) * @date 2016-08-11 07:12:14 */ //冒泡排序法 ...

  6. 十大基础排序算法[java源码+动静双图解析+性能分析]

    一.概述 作为一个合格的程序员,算法是必备技能,特此总结十大基础排序算法.java版源码实现,强烈推荐<算法第四版>非常适合入手,所有算法网上可以找到源码下载. PS:本文讲解算法分三步: ...

  7. 基础排序算法之快速排序(Quick Sort)

    快速排序(Quick Sort)同样是使用了分治法的思想,相比于其他的排序方法,它所用到的空间更少,因为其可以实现原地排序.同时如果随机选取中心枢(pivot),它也是一个随机算法.最重要的是,快速排 ...

  8. 基础排序算法之并归排序(Merge Sort)

    并归排序是学习分治法 (Merge Sort) 的好例子.而且它相对于选择,插入,冒泡排序来说,算法性能有一定提升.我首先会描述要解决的问题,并给出一个并归排序的例子.之后是算法的思路以及给出伪代码. ...

  9. ZH奶酪:【数据结构与算法】基础排序算法总结与Python实现

    1.冒泡排序(BubbleSort) 介绍:重复的遍历数列,一次比较两个元素,如果他们顺序错误就进行交换. 2016年1月22日总结: 冒泡排序就是比较相邻的两个元素,保证每次遍历最后的元素最大. 排 ...

随机推荐

  1. C语言学习<输入输出函数,函数的调用>

    #include <stdio.h> /* 输入输出函数的学习 函数的调用 2017.05.25 soulsjie */ //输入连个数字求最大值 void main(){ int Max ...

  2. hdu 4430 二分+枚举

    /* 二分+枚举 枚举k会超时,枚举r还要优化,有可能会超64 */ #include<stdio.h> #include<math.h> #define ll __int64 ...

  3. MySQL Workbench基本操作

    MySQL Workbench是一款专为MySQL设计的ER/数据库建模工具.它是著名的数据库设计工具DBDesigner4的继任者.你可以用MySQL Workbench设计和创建新的数据库图示,建 ...

  4. android studio配置so文件路径

    将一个项目从eclipse上移植到android studio时,发现总是加载不成功库文件,so库文件放在了main/src/libs下的目录. 参考网上资料,studio默认的库文件路径是main/ ...

  5. 【BZOJ4868】期末考试(整数三分)

    题意: 有n位同学,每位同学都参加了全部的m门课程的期末考试,都在焦急的等待成绩的公布.第i位同学希望在第ti天 或之前得知所.有.课程的成绩.如果在第ti天,有至少一门课程的成绩没有公布,他就会等待 ...

  6. ci框架(codeigniter)Email发送邮件、收件人、附件、Email调试工具

        ci框架(codeigniter)Email发送邮件.收件人.附件.Email调试工具 Email 类         CodeIgniter 拥有强大的 Email 类来提供如下的功能: 多 ...

  7. Remove Duplicates from Sorted Array(参考)

    Given a sorted array, remove the duplicates in place such that each element appear only once and ret ...

  8. Java 代理模式和装饰者模式的区别

    装饰模式:以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案:代理模式:给一个对象提供一个代理对象,并有代理对象来控制对原有对象的引用: 装饰模式应该为所装饰的对象增强功能:代理模式对代理的 ...

  9. 用Visual Studio 2010 打开Visual Studio 2013 (C#专用)

    1.更改.sln 1)将Microsoft Visual Studio Solution File, Format Version 12.00   改成11.00 2)将 # Visual Studi ...

  10. 条款八: 写operator new和operator delete时要遵循常规

    自己重写operator new时(条款10解释了为什么有时要重写它),很重要的一点是函数提供的行为要和系统缺省的operator new一致.实际做起来也就是:要有正确的返回值:可用内存不够时要调用 ...