【t099】最接近神的人

Time Limit: 1 second
Memory Limit: 128 MB

【问题描述】

破解了符文之语,小FF开启了通往地下的道路。当他走到最底层时,发现正前方有一扇巨石门,门上雕刻着一幅古代人进行某种活
动的图案。而石门上方用古代文写着“神的殿堂”。小FF猜想里面应该就有王室的遗产了。但现在的问题是如何打开这扇门…
… 仔细研究后,他发现门上的图案大概是说:古代人认为只有智者才是最容易接近神明的。
而最聪明的人往往通过一种仪式选拔出来。仪式大概是指,即将隐退的智者为他的候选人写下一串无序的数字,并让他们进行一种
操作,即交换序列中相邻的两个元素。而用最少的交换次数使原序列变成不下降序列的人即是下一任智者。
小FF发现门上同样有着n个数字。于是他认为打开这扇门的秘诀就是找到让这个序列变成不下降序列所需要的最小次数。但小FF
不会……只好又找到了你,并答应事成之后与你三七分……
样例说明:开始序列为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≤104。
对于100%的数据 1≤n≤5*10
【输入格式】

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

【输出格式】

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

Sample Input

4
2 8 0 3

Sample Output

3

【题目链接】:http://noi.qz5z.com/viewtask.asp?id=t099

【题解】

把n个数字变成有序;(只能交换相邻的数字);
考虑n个数字中最大的位置(最后要换到最后一个位置);
肯定是一个一个往后换(因为是最大的,所以就是它后面的逆序对个数比它小却在它后面的数字的个数);
然后把那个数字剔除掉(变成n-1个数字);
在这n-1个数字里面再找一个最大的(重复上述过程);
这个时候原来那个最大的数字已经去掉了;
所以这个原本第二大的元素(现在变成最大的了);
它也要放在第n-1个位置;
则它需要往后交换的次数也是它的逆序对个数(那个最大的数肯定不在它的逆序对里面,因为如果是最大的,那它不可能满足在它后面且比它小这个条件->现在你是第二大的!);
因为我们在做上面这个事情的过程中,不断把最大的数字返回到它应有的位置,而那些不该在那么后面的元素也被相应的交换到了前面(所以咱们没有做任何一件无意义的事情;所以我们得到的是最优解,渣渣只能这样骗自己了);
给个例子
在4个数中找最大的
4 9 5 2
9先移->9的逆序数为2;
4 5 2 9
然后不看9了;
在前3个数字中找最大的
5的逆序数为1;
4 2 5 9
….
就算9在5的后面,5的逆序数也是1!
逆序对用归并排序搞就好;
再给个线段树的链接http://blog.csdn.net/harlow_cheng/article/details/52453361

【完整代码】

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <set>
#include <map>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
#include <stack>
#include <string>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define LL long long
#define rep1(i,a,b) for (int i = a;i <= b;i++)
#define rep2(i,a,b) for (int i = a;i >= b;i--)
#define mp make_pair
#define pb push_back
#define fi first
#define se second

typedef pair<int,int> pii;
typedef pair<LL,LL> pll;

void rel(LL &r)
{
    r = 0;
    char t = getchar();
    while (!isdigit(t) && t!='-') t = getchar();
    LL sign = 1;
    if (t == '-')sign = -1;
    while (!isdigit(t)) t = getchar();
    while (isdigit(t)) r = r * 10 + t - '0', t = getchar();
    r = r*sign;
}

void rei(int &r)
{
    r = 0;
    char t = getchar();
    while (!isdigit(t)&&t!='-') t = getchar();
    int sign = 1;
    if (t == '-')sign = -1;
    while (!isdigit(t)) t = getchar();
    while (isdigit(t)) r = r * 10 + t - '0', t = getchar();
    r = r*sign;
}

const int MAXN = 5*10e5+100;
const int dx[5] = {0,1,-1,0,0};
const int dy[5] = {0,0,0,-1,1};
const double pi = acos(-1.0);
int n;
LL ans = 0,a[MAXN],temp[MAXN];

void mergesort(int l,int r)
{
    if (l==r) return;
    int m = (l+r)>>1;
    mergesort(l,m);mergesort(m+1,r);
    int i = l,j = m+1,k = i;
    while (i <= m && j <= r)
        if (a[i]>a[j])
            temp[k++] = a[j++],ans+=m-i+1;
        else
            temp[k++] = a[i++];
    while (i <= m) temp[k++] = a[i++];
    while (j <= r) temp[k++] = a[j++];
    for (int i = l;i<= r;i++)
        a[i] = temp[i];
}

int main()
{
   // freopen("F:\rush.txt","r",stdin);
    rei(n);
    rep1(i,1,n)
        rel(a[i]);
    mergesort(1,n);
    cout << ans << endl;
    return 0;
}
原文地址:https://www.cnblogs.com/AWCXV/p/7626936.html