ICPC Central Russia Regional Contest (CRRC 19)

K. Parabolic sorting

题意:给你一个数组,要你重新排序这个数组使得最终的数组前一部分单调递减,后一部分单调递增。

每次操作可以改变相邻位置的两个数。问你最小操作数。

刚开始的错误想法是把直接把数组分为两个部分,前一部分排序的操作数加上后一部分的操作数,取最小值。

正解是:对于每个数取min(前部分小于它的个数,后部分小于它的个数),加起来即是答案。

用树状数组写食用更加哦!

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
const int mod=998244353;
const double ep=1e-8;
#define PLI pair<ll,int>
#define pb push_back
#define mk make_pair
#define fi first
#define se second
int n,b[maxn],b1[maxn];
struct node{
    int l,r,sum;
}a[maxn<<2];
void build(int k,int l,int r)
{
    a[k].l=l;a[k].r=r;
    a[k].sum=0;
    if(l==r)return;
    int mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
}
void pushup(int k)
{
    a[k].sum=a[k<<1].sum+a[k<<1|1].sum;
}
void update(int k,int x)
{
    if(a[k].l==x&&a[k].r==x)
    {
        a[k].sum=1;return;
    }
    int mid=(a[k].l+a[k].r)>>1;
    if(x<=mid)update(k<<1,x);
    else update(k<<1|1,x);
    pushup(k);
}
int query(int k,int l,int r)
{
    if(a[k].l>=l&&a[k].r<=r)return a[k].sum;
    int mid=(a[k].l+a[k].r)>>1;
    int sum=0;
    if(l<=mid)sum=query(k<<1,l,r);
    if(r>mid)sum+=query(k<<1|1,l,r);
    return sum;
}
ll res,l[maxn],r[maxn];
void solve()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&b[i]),b1[i]=b[i];
    sort(b1+1,b1+1+n);
    for(int i=1;i<=n;i++)b[i]=lower_bound(b1+1,b1+1+n,b[i])-b1;
    build(1,1,n);
    for(int i=1;i<=n;i++)
    {
        int k=query(1,1,b[i]);
        l[i]=k;
        update(1,b[i]);
    }
    build(1,1,n);
    for(int i=n;i>=1;i--)
    {
        int k=query(1,1,b[i]);
        r[i]=k;
        update(1,b[i]);
    }
    res=0;
    for(int i=1;i<=n;i++)
    {
        res=res+min(l[i],r[i]);
    }
    printf("%lld\n",res);
}

int main()
{
    int T=1;
//    scanf("%d",&T);
    while(T--)solve();    
}

 

posted @ 2020-12-10 17:20  芥么拉  阅读(224)  评论(0编辑  收藏  举报