https://www.zybuluo.com/ysner/note/1289967

题面

定义"翻转排序":每次操作均为把区间\([l,r]\)中所有数倒过来,即\(swap(a[l],a[r])+swap(a[l+1],a[r-1])+...\)。

每次操作的代价为\(r-l+1\)。

给一个序列\(a\),用"翻转排序"给它排序,并把代价控制在\(2*10^7\)以内。

  • \(60pts\) \(n\leq5000\)
  • \(ex25pts\) \(a[i]\in\{0,1\}\)
  • \(100pts\) \(n\leq5*10^4\)

解析

感觉很符合\(noip\_T2\)难度。。。

\(60pts\)算法

仔细想想,"翻转"这个条件挺恶心的。

可以不"翻转"吗?那就只能交换相邻两个。

把序列扫\(n\)遍,每次只交换序列中相邻两个数。

这样每交换一次对应着消除一个逆序对,复杂度可控。

次数最多为\((n-1)*[(n-1)-1]/2\leq1.25*10^7\)

但是我并不知道这种排序名字叫什么。。。

复杂度\(O(n^2)\)

代码在下一档。

\(85pts\)算法

这个有点搞笑。

直接归并排序就可以了。

每次归并后把左边的\(1\)区间和右边的\(0\)区间并在一起,翻转即可。

复杂度\(O(nlogn)\)

贴上代码。

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define ll long long
#define re register
#define il inline
#define pc(a) putchar(a)
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int N=1e5+100;
int n,a[N];
il ll gi()
{
re ll x=0,t=1;
re char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') t=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x*t;
}
il void wri(re int x)
{
if(x>9) wri(x/10);
pc(x%10+48);
}
il void solve(re int l,re int r)
{
if(l==r) return;
if(l==r-1)
{
if(a[l]>a[r]) swap(a[l],a[r]),printf("%d %d\n",l,r);
return;
}
re int mid=l+r>>1,p1=0,p2=0;
solve(l,mid);solve(mid+1,r);
fp(i,l,mid) if(a[i]==1) {p1=i;break;}
fp(i,mid+1,r) if(a[i]==1) {p2=i;break;}
if(!p1) return;
if(!p2) {printf("%d %d\n",p1,r);reverse(a+p1,a+r+1);return;}
printf("%d %d\n",p1,p2-1);reverse(a+p1,a+p2);
return;
}
int main()
{
n=gi();
fp(i,1,n) a[i]=gi();
if(n<=5000)
{
fp(i,1,n)
{
re int tag=0;
fp(j,1,n-1)
if(a[j]>a[j+1]) tag=1,wri(j),pc(' '),wri(j+1),pc('\n'),swap(a[j],a[j+1]);
if(!tag) break;
}
puts("-1 -1");
return 0;
}
solve(1,n);
puts("-1 -1");
return 0;
}

\(100pts\)算法

蒟蒻其实并不知道快排原理

快排的原理是,在向下分治前,先选取一个基准数,通过归并排序,把该分治区间中的小于等于其的数移到左边,大于其的数移到右边。

归并的过程中可以通过"翻转",把左区间中的大于其的数与右区间中小于等于其的数一次交换完毕。

然后继续向下分治即可。

基准数就是选,该区间中间位置,在排序完后的\(a\)中对应的值。(记得把值离散化)

复杂度\(O(nlog^2n)\)。

很对但是想不到。。。

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define ll long long
#define re register
#define il inline
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int N=1e5+100;
ll n,a[N],b[N];
il ll gi()
{
re ll x=0,t=1;
re char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') t=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x*t;
}
il int Qsort(re int l,re int r,re ll B)
{
if(l==r) return l+(a[l]<=B);
re int mid=l+r>>1,p1=Qsort(l,mid,B),p2=Qsort(mid+1,r,B)-1;
if(p1!=mid+1&&p2!=mid)
{
printf("%d %d\n",p1,p2);
reverse(a+p1,a+p2+1);
}
return p1+(p2-mid);
}
il void solve(re int l,re int r)
{
if(l==r) return;
re int mid=l+r>>1;
Qsort(l,r,b[mid]);
solve(l,mid);solve(mid+1,r);
}
int main()
{
n=gi();
fp(i,1,n) b[i]=a[i]=gi()*n+i;
sort(b+1,b+1+n);
solve(1,n);
puts("-1 -1");
return 0;
}

最新文章

  1. JAVA自定义注解
  2. STL学习之vector
  3. Java BigDecimal和double
  4. LoadRunner 12.02 安装教程及中文语言包安装
  5. 【云计算】qcow2虚拟磁盘映像转化为vmdk
  6. 剑指offer题目41-50
  7. (step5.1.3)hdu 1213( How Many Tables——1213)
  8. SpringMVC详解(六)------与json交互
  9. [转]压缩感知重构算法之分段正交匹配追踪(StOMP)
  10. KMP算法小结
  11. spring mvc 简单的文件上传与下载
  12. Python下划线简介
  13. 【转】http的keep-alive和tcp的keepalive区别
  14. 源码调试debug_info 的作用和使用方法
  15. UVA 10382 Watering Grass(区间覆盖,贪心)题解
  16. git for c#,文件改动内容
  17. Linux 命令 统计进程数目
  18. Linux入门基础(一):Linux基本操作
  19. Kotlin Reference (四) Basic Types
  20. HDU 2665.Kth number-可持久化线段树(无修改区间第K小)模板 (POJ 2104.K-th Number 、洛谷 P3834 【模板】可持久化线段树 1(主席树)只是输入格式不一样,其他几乎都一样的)

热门文章

  1. Buffer.concat()
  2. 15Spring泛型依赖注入
  3. 第十八节:Scrapy爬虫框架之settings文件详解
  4. 集训第四周(高效算法设计)M题 (扫描法)
  5. Unity 3D 使用TerrainCompose 调用RTP 报错:
  6. JavaScript编程那些事(牛客网 LeetCode)
  7. python gdal库安装
  8. Windows Server 2012 防火墙如何添加端口例外的方法(转)
  9. MySQL Workbench基本操作
  10. python: filter, map, reduce, lambda