P1774 最接近神的人
题目描述
破解了符文之语,小 FF 开启了通往地下的道路。当他走到最底层时,发现正前方有一扇巨石门,门上雕刻着一幅古代人进行某种活动的图案。而石门上方用古代文写着“神的殿堂”。小 FF 猜想里面应该就有王室的遗产了。但现在的问题是如何打开这扇门……。
仔细研究后,他发现门上的图案大概是说:古代人认为只有智者才是最容易接近神明的。而最聪明的人往往通过一种仪式选拔出来。仪式大概是指,即将隐退的智者为他的候选人写下一串无序的数字,并让他们进行一种操作,即交换序列中相邻的两个元素。而用最少的交换次数使原序列变成不下降序列的人即是下一任智者。
小 FF 发现门上同样有着 n n n 个数字。于是他认为打开这扇门的秘诀就是找到让这个序列变成不下降序列所需要的最小次数。但小 FF 不会……只好又找到了你,并答应事成之后与你三七分……
输入格式
第一行为一个整数 n n n,表示序列长度。
第二行为 n n n 个整数,表示序列中每个元素。
输出格式
一个整数 a n s \mathit{ans} ans,即最少操作次数。
输入输出样例 #1
输入 #1
4
2 8 0 3
输出 #1
3
说明/提示
数据范围及约定
- 对于 30 % 30\% 30% 的数据 1 ≤ n ≤ 1 0 4 1≤n≤10^4 1≤n≤104。
- 对于 100 % 100\% 100% 的数据 1 ≤ n ≤ 5 × 1 0 5 1≤n≤5\times 10^5 1≤n≤5×105, A i ∈ [ − 2 31 , 2 31 ) A_i\in [-2^{31}, 2^{31}) Ai∈[−231,231)。
样例解释
开始序列为 [ 2 , 8 , 0 , 3 ] [2,8,0,3] [2,8,0,3],目标序列为 [ 0 , 2 , 3 , 8 ] [0, 2, 3, 8] [0,2,3,8],可进行三次操作的目标序列:
- 交换 ( 8 , 0 ) (8,0) (8,0),序列变成 [ 2 , 0 , 8 , 3 ] [2,0,8,3] [2,0,8,3];
- 交换 ( 2 , 0 ) (2,0) (2,0),序列变成 [ 0 , 2 , 8 , 3 ] [0,2,8,3] [0,2,8,3];
- 交换 ( 8 , 3 ) (8,3) (8,3),序列变成 [ 0 , 2 , 3 , 8 ] [0,2,3,8] [0,2,3,8]。
C++实现
#include<bits/stdc++.h>
using namespace std;
int n,a[600000],b[600000];
long long ans;
void merge_sort(int l,int r){
if (l==r) return;
int mid=(l+r)/2;
//往下递归
merge_sort(l,mid);
merge_sort(mid+1,r);
//排序
int i=l,j=mid+1,k=l;//操作更新的是l->r的区间 初值赋在l和r
while (i<=mid&&j<=r){//在底层递归结束之后 前后两个部分都应该是有序的
if (a[i]<=a[j]) {
b[k]=a[i];//把较小的数据放入辅助数组
i++;
k++;
}
else {
b[k]=a[j];
ans+=mid-i+1;//前一半是有序的那么这个后面的都是逆序对
j++;
k++;
}
}
//剩余元素加入数组
while(i<=mid) {
b[k]=a[i];
k++;
i++;
}
while (j<=r){
b[k]=a[j];
k++;
j++;
}
for (int p=l;p<=r;p++) a[p]=b[p];
}
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
merge_sort(1,n);
printf("%lld\n",ans);
return 0;
}
后续
接下来我会不断用C++来实现信奥比赛中的算法题、GESP考级编程题实现、白名单赛事考题实现,记录日常的编程生活、比赛心得,感兴趣的请关注,我后续将继续分享相关内容