题意:标题就是逆序对的意思,大意就是有一个序列a(是1 - n的一个全排列),然后我们可以对它的每一个元素选择加1或保持不变,问操作完之后最少的逆序对数并输出。
步骤:①对于可以选择的{0, 1}操作,如果a_j = a_i+1(j > i),此时a_j+ 1的话就可以减少一对逆序数。可以 bool 一个 f [ ] 数组,第 i 个元素出现则将 f [ a[ i ] ] = true; if f [ a [ i ] +1 ] = true,此时将a [ i ] + 1;
②按①处理完之后,采用归并排序求逆序数。 O(nlogn)
accode:
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 10;
int a[maxn];
bool f[maxn];
ll ans = 0;
void merge2(int q[], int l, int mid, int r)
{
int lindex = l, rindex = mid + 1;
int *team = new int[r-l+1];
int teamindex = 0;
while(lindex <= mid && rindex <= r)
{
if(q[lindex] <= q[rindex])
team[teamindex++] = q[lindex++];
else{
team[teamindex++] = q[rindex++];
ans += mid - lindex + 1;//求逆序对数
}
}
while(lindex <= mid)
{
team[teamindex++] = q[lindex++];
}
while(rindex <= r)
{
team[teamindex++] = q[rindex++];
}
for(int i = 0; i < teamindex; i++)
{
q[l + i] = team[i];
}
}
void merge1(int q[], int l, int r)
{
int mid = (l + r) / 2;
if(l < r)
{
merge1(q, l, mid);
merge1(q, mid + 1, r);
merge2(q, l, mid, r);
}
//else return;
}
int main()
{
int n;
scanf("%d", &n);
for(int i = 0; i < n; i++)
scanf("%d", &a[i]);
f[a[0]] = true;//已出现的元素标记为true
for(int i = 1; i < n; ++i)
{
if(f[a[i]+1])
a[i]+=1;
else
f[a[i]] = true;
}
merge1(a, 0, n-1);
printf("%lld\n", ans);
return 0;
}