携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第24天,点击查看活动详情
最接近神的人
题目描述
破解了符文之语,小FF开启了通往地下的道路。当他走到最底层时,发现正前方有一扇巨石门,门上雕刻着一幅古代人进行某种活动的图案。而石门上方用古代文写着“神的殿堂”。小FF猜想里面应该就有王室的遗产了。但现在的问题是如何打开这扇门……
仔细研究后,他发现门上的图案大概是说:古代人认为只有智者才是最容易接近神明的。而最聪明的人往往通过一种仪式选拔出来。仪式大概是指,即将隐退的智者为他的候选人写下一串无序的数字,并让他们进行一种操作,即交换序列中相邻的两个元素。而用最少的交换次数使原序列变成不下降序列的人即是下一任智者。
小FF发现门上同样有着n个数字。于是他认为打开这扇门的秘诀就是找到让这个序列变成不下降序列所需要的最小次数。但小FF不会……只好又找到了你,并答应事成之后与你三七分……
输入格式
第一行为一个整数n,表示序列长度
第二行为n个整数,表示序列中每个元素。
输出格式
一个整数ans,即最少操作次数。
样例 #1
样例输入 #1
4
2 8 0 3
样例输出 #1
3
提示
对于30%的数据1≤n≤10^4。
对于100%的数据1≤n≤5*10^5;
-maxlongint≤A[i]≤maxlongint。
样例说明:开始序列为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
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#define WA AC
#define RE AC
#define CE AC
#define TLE AC
#define MLE AC
using namespace std;
inline int read ()
{
int f = 1, x = 0;
char ch;
do {ch = getchar (); if (ch== '-') f = -1;} while (ch < '0' || ch > '9');
do {x = x * 10 + ch - '0'; ch = getchar ();} while (ch >= '0' && ch <= '9');
return f * x;
}
const int N = 5 * (1e5 + 7);
typedef long long ll;
ll n;
ll a[N];
ll xv[N];
ll tree[N];
ll ans;
inline bool cmp (int a, int b)//这里的cmp我们需要判重,然后按照原本的顺序排列,要不sort会出玄学乱排
{
return xv[a] == xv[b] ? a > b : xv[a] > xv[b];
}
inline int lb (int x)//lowbit
{
return x & -x;
}
inline void go_and_do_it (int x)//单点修改 ,每次加1
{
for (int i = x; i <= n; i += lb (i))
tree[i] ++;
}
inline int find (int x)//查询
{
int sum = 0;
for (int i = x; i > 0; i -= lb (i))
sum += tree[i];
return sum;
}
int main ()
{
n = read ();
for (int i = 1; i <= n; i ++)
{
xv[i] = read ();
a[i] = i;//对其进行初始化先化成自己在进行排序
}
sort (a + 1 , a + 1 + n, cmp);//对其进行排序
for (int i = 1 ; i <= n; i ++)
{
go_and_do_it (a[i]);//把数插到树状数组里面
ans += find (a[i] - 1);// 每次查询把前缀和加到ans里面
}
printf ("%lld", ans);
return 0;
}