LCIS - 构造 - 分治

本文介绍了一种使用区间翻转操作进行排序的算法,通过选定一个基准数,将序列中小于等于基准数的元素置于左侧,大于基准数的元素置于右侧,采用类似归并排序的分治策略,实现序列的快速排序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意:
给你一个序列,长度不超过32000,要求用不超过4e6的代价将其排序。
你可以进行的操作形如选定一个区间然后翻转,代价是区间长度。
题解:
考虑快排,现在选定了一个数字(实际应该选择离散化后的中位数),要将小于等于他的放左边,大于放右边。这个怎么搞,你将小于等于的看做0,大于看做1,相当于是把一个01序列排序,这个可以搞一个类似于归并的分治。总复杂度两个log,实现优秀可以通过。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
const int N=33000;
int a[N],b[N];vector<pii> lst;
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
inline int rev(int s,int t)
{
    lst.pb(mp(s,t));
    for(int i=s,j=t;i<=j;i++,j--) swap(a[i],a[j]);
    return 0;
}
int mysort(int l,int r,int x)
{
    if(l>=r) return 0;
    int mid=(l+r)>>1;
    mysort(l,mid,x);
    mysort(mid+1,r,x);
    int p=l,q=mid;
    while(p<=mid&&a[p]<=x) p++;
    while(q<r&&a[q+1]<=x) q++;
    if(p<=mid&&mid<q) rev(p,q);
    return 0;
}
int solve(int l,int r)
{
    if(l>=r) return 0;int cnt=0;
    rep(i,l,r) b[++cnt]=a[i];
    sort(b+1,b+cnt+1);
    cnt=unique(b+1,b+cnt+1)-b-1;
    if(cnt==1) return 0;
    int x=b[cnt/2];
    mysort(l,r,x);int p=l;
    rep(i,l,r) if(a[i]<=x) p=i;
    solve(l,p),solve(p+1,r);
    return 0;
}
int main()
{
    int n=inn();
    rep(i,1,n) a[i]=inn();
    solve(1,n);
    printf("%d\n",int(lst.size()));
    Rep(i,lst) printf("%d %d\n",lst[i].fir,lst[i].sec);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值