【JZOJ B组】【NOIP2013模拟联考5】休息(rest)

2 篇文章 0 订阅
2 篇文章 0 订阅

Description

休息的时候,可以放松放松浑身的肌肉,打扫打扫卫生,感觉很舒服。在某一天,某LMZ 开始整理他那书架。已知他的书有n 本,从左到右按顺序排列。他想把书从矮到高排好序,而每一本书都有一个独一无二的高度Hi。他排序的方法是:每一次将所有的书划分为尽量少的连续部分,使得每一部分的书的高度都是单调下降,然后将其中所有不少于2 本书的区间全部翻转。重复执行以上操作,最后使得书的高度全部单调上升。可是毕竟是休息时间,LMZ 不想花太多时间在给书排序这种事上面。因此他划分并翻转完第一次书之后,他想计算,他一共执行了多少次翻转操作才能把所有的书排好序。LMZ 惊奇地发现,第一次排序之前,他第一次划分出来的所有区间的长度都是偶数。

Input

第一行一个正整数n, 为书的总数。

接下来一行n个数,第i个正整数Hi,为第i 本书的高度。

Output

仅一个整数,为LMZ 需要做的翻转操作的次数。

Sample Input

6

5 3 2 1 6 4

Sample Output

3

【样例解释】

第一次划分之后,翻转(5,3,2,1),(6,4)。之后,书的高度为1 2 3 5 4 6,然后便是翻转(5,4)即可。

Data Constraint

对于10%的数据:n<=50

对于40%的数据:n<=3000

对于100%的数据:1<=n<=100000, 1<=Hi<=n

思路

首先,我们把所有降序的区间全部反过来。
然后我们发现,只有区间临界点的数字不满足单调递增。
容易想到逆序对。

注意:不要打memset,否则会TLE 还我60分!!!

代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=100077,inf=0x3f3f3f3f;
int a[maxn],n,b[maxn];
long long ass;
void change(int l,int r)
{
    for(int i=1; i<=(r-l+1)/2; i++) swap(a[l+i-1],a[r-i+1]);
}
void init()
{
    int t=1;
    for(int i=2; i<=n+1; i++)
    {
        if(a[i]>a[i-1])
        {
            ass++;
            change(t,i-1);
            t=i;
        }
    }
}
/*void gb(int l,int mid,int r)
{
    memset(x,0,sizeof(x));
    memset(y,0,sizeof(y));
    for(int i=l; i<=mid; i++) x[++x[0]]=a[i]; x[0]=1;
    for(int i=mid+1; i<=r; i++) y[++y[0]]=a[i]; y[0]=1;
    for(int i=l; i<=r; i++)
    {
        if(x[0]<=mid-l+1&&y[0]<=r-mid)
        {
            if(x[x[0]]<y[y[0]]) a[i]=x[x[0]++];else
            if(x[x[0]]>y[y[0]])
            {
                a[i]=y[y[0]++];
                ass+=mid-x[0]-l+2;
            }
        }else
        {
            if(x[0]<=mid) a[i]=x[x[0]++];
            if(y[0]<=r) a[i]=y[y[0]++];
        }
    }
}*/
void sort(int l,int r)
{
    if(l>=r) return;
    int mid=(l+r)>>1;
    sort(l,mid);
    sort(mid+1,r);
    int x1=l,x2=mid+1;
    b[0]=0;
    while(x1<=mid&&x2<=r)
    {
//      int x=a[x1],y=a[x2];
        if(a[x1]<a[x2]) b[++b[0]]=a[x1++];else
        if(a[x1]>a[x2])
        {
            b[++b[0]]=a[x2++];
            ass+=mid-x1+1;
        }
    }
    for(int i=x2; i<=r; i++) b[++b[0]]=a[i];
    for(int i=x1; i<=mid; i++) b[++b[0]]=a[i];
    for(int i=l; i<=r; i++) a[i]=b[i-l+1];
    b[0]=0;
}
int main()
{
    scanf("%d",&n);
    for(int i=1; i<=n; i++) scanf("%d",&a[i]);
    a[n+1]=inf;
    init();
    sort(1,n);
    printf("%lld\n",ass);
//  for(int i=1; i<=n; i++) printf("%d ",a[i]);
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值