【洛谷P1774】最接近神的人_NOI导刊2010提高(02)

题目描述

破解了符文之语,小FF开启了通往地下的道路。当他走到最底层时,发现正前方有一扇巨石门,门上雕刻着一幅古代人进行某种活动的图案。而石门上方用古代文写着“神的殿堂”。小FF猜想里面应该就有王室的遗产了。但现在的问题是如何打开这扇门……

仔细研究后,他发现门上的图案大概是说:古代人认为只有智者才是最容易接近神明的。而最聪明的人往往通过一种仪式选拔出来。仪式大概是指,即将隐退的智者为他的候选人写下一串无序的数字,并让他们进行一种操作,即交换序列中相邻的两个元素。而用最少的交换次数使原序列变成不下降序列的人即是下一任智者。

小FF发现门上同样有着n个数字。于是他认为打开这扇门的秘诀就是找到让这个序列变成不下降序列所需要的最小次数。但小FF不会……只好又找到了你,并答应事成之后与你三七分……

输入输出格式

输入格式:

 

第一行为一个整数n,表示序列长度

第二行为n个整数,表示序列中每个元素。

 

输出格式:

 

一个整数ans,即最少操作次数。

 

输入输出样例

输入样例#1:
4
2 8 0 3
输出样例#1:
3
   样例说明:开始序列为2 8 0 3,目标序列为0 2 3 8,可进行三次操作的目标序列:
    1.Swap (8,0):2  0  8  3
    2.Swap (2,0):0  2  8  3
    3.Swap (8,3):0  2  3  8

说明

对于30%的数据1≤n≤10^4。

对于100%的数据1≤n≤5*10^5;

-maxlongint≤A[i]≤maxlongint。

题解:

裸的逆序对问题,其实本题和codevs1688求逆序对是同一题,两题代码都一样。

归并排序求逆序对的模板,推荐一篇很好的归并排序求逆序对的文章:http://blog.csdn.net/acdreamers/article/details/16849761

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=500000+5;
typedef long long ll;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n;
int a[maxn],tmp[maxn];
ll ans;
inline void merge(int x,int mid,int y)
{
    int i=x,j=mid+1,k=x;
    while(i<=mid&&j<=y)
    {
        if(a[i]>a[j])
        {
            tmp[k++]=a[j++];
            ans+=mid-i+1;
        }
        else
        tmp[k++]=a[i++];
    }
    while(i<=mid) tmp[k++]=a[i++];
    while(j<=y) tmp[k++]=a[j++];
    for(int i=x;i<=y;i++) a[i]=tmp[i];
}
void merge_sort(int x,int y)
{
    if(x<y)
    {
        int mid=(x+y)>>1;
        merge_sort(x,mid);
        merge_sort(mid+1,y);
        merge(x,mid,y);
    }
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++) a[i]=read();
    merge_sort(1,n);
    printf("%lld\n",ans);
    return 0;
}
归并排序求逆序对

 

树状数组求逆序对,本题有相同的情况,如果直接用sort函数会错的。

可以进行去重操作,但未免太麻烦,直接用stable_sort就行了,可以百度一下,与sort的区别就是不改变相同元素的位置,如果用sort会增添逆序对的个数,因为sort有可能改变相同元素的位置,那么相同元素有可能就成为了逆序对。

还有一种方法就是在自定义比较函数里面增加一个如果两个元素的值相等,那么比较两个元素的编号就行了。

具体操作看代码:

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=500000+5;
typedef long long ll;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n;
int b[maxn],c[maxn];
struct node
{
    int x,id;
    bool operator < (const node &j) const {
        return x<j.x;
    }
}a[maxn];
inline int lowbit(int x){return x&(-x);}
inline void update(int x,int d)
{
    while(x<=n)
    {
        c[x]+=d;
        x+=lowbit(x);
    }
}
inline int getsum(int x)
{
    int tmp=0;
    while(x)
    {
        tmp+=c[x];
        x-=lowbit(x);
    }
    return tmp;
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
    {
        a[i].x=read();
        a[i].id=i;
    }
    stable_sort(a+1,a+n+1);
    for(int i=1;i<=n;i++) b[a[i].id]=i;
    ll ans=0;
    for(int i=1;i<=n;i++)
    {
        update(b[i],1);
        ans+=i-getsum(b[i]);
    }
    printf("%lld\n",ans);
    return 0;
}
    
stable_sort

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=500000+5;
typedef long long ll;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n;
int b[maxn],c[maxn];
struct node
{
    int x,id;
    bool operator < (const node &j) const {
        return (x==j.x? id<j.id : x<j.x);
    }
}a[maxn];
inline int lowbit(int x){return x&(-x);}
inline void update(int x,int d)
{
    while(x<=n)
    {
        c[x]+=d;
        x+=lowbit(x);
    }
}
inline int getsum(int x)
{
    int tmp=0;
    while(x)
    {
        tmp+=c[x];
        x-=lowbit(x);
    }
    return tmp;
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
    {
        a[i].x=read();
        a[i].id=i;
    }
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++) b[a[i].id]=i;
    ll ans=0;
    for(int i=1;i<=n;i++)
    {
        update(b[i],1);
        ans+=i-getsum(b[i]);
    }
    printf("%lld\n",ans);
    return 0;
}
自定义比较函数

 

posted @ 2017-08-05 20:56  沐灵_hh  阅读(218)  评论(0编辑  收藏  举报