近日C国某领海主权屡次被境外反动势力挑衅,中央军委决定进行两栖登岛作战演习以震慑国内外反动势力。在某个作战演习过程中,有n支不同规模的我方部队在敌国境内进行战斗演习,他们的作战编号是1~n。现在需要集结优势兵力,各个歼灭敌方残余势力。为了保证我方整体灵活性,wz决定选出两支队伍进行组排。为方便组排,规定只能由规模较大的部队带领编号比他大的且规模严格比他小的部队进行作战演习。假如你是此次军事行动的总指挥wz,请问你知道有多少对可以组排的队伍吗?
输入格式:
第一行,一个数n,表示有n支部队。
第二行n个数,表示每支部队的军事规模大小。序列中每个数字不超过 10^9
输出格式:
输出存在多少对可以两两组排的部队。
输入样例:
6
5 4 2 6 3 1
输出样例:
11
这题实质就是求逆序对,求逆序对有四种方法:
- 冒泡排序(会有测试点超时):没交换一次,结果就加一次
- 归并排序:时间复杂度O(nlogn),大部分题都不会超时
- 离散化+树状数组
- 线段树
第三种和第四种算法参考逆序对的三种求法
参考代码:
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
ll sum=0;
int a[500100];
ll merge(int l,int mid,int r){
int i=l,j=mid;
int t=0;
ll k=0;
int b[r-l+1];
int index=0;
while(i<mid&&j<=r){
if(a[i]>a[j]){
b[index++]=a[j++];
t++;
}
if(a[i]<=a[j]||j==r+1){
k+=t*(mid-i);
b[index++]=a[i++];
t=0;
}
}
while(i<mid) b[index++]=a[i++];
while(j<=r) b[index++]=a[j++];
index=0;
for(i=l;i<=r;i++)
a[i]=b[index++];
return k;
}
void mergesort(int l,int r){
if(l>=r) return ;
int mid=(l+r)/2;
mergesort(l,mid);
mergesort(mid+1,r);
sum+=merge(l,mid+1,r);
}
int main(void){
std::ios::sync_with_stdio(false);
std::cin.tie(0);
int n;cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
mergesort(0,n-1);
cout<<sum<<endl;
}
//冒泡有一个测试点超时
// #include<iostream>
// using namespace std;
// typedef long long ll;
// int main(void){
// int n;cin>>n;
// ll sum=0;
// int a[n];
// for(int i=0;i<n;i++) cin>>a[i];
// for(int i=1;i<n;i++){
// int flag=0;
// for(int j=0;j<n-i;j++){
// if(a[j]>a[j+1]){
// int temp=a[j+1];
// a[j+1]=a[j];
// a[j]=temp;
// flag=1;
// sum++;
// }
// }
// if(flag==0) break;
// }
// cout<<sum<<endl;
// }