Inverse Pair
题意:
一个数组a,现在构造一个数组c,c[i]=a[i]+0/1(0或1),使得c的逆序对最少
题解:
如果x在x+1的后面,我们让x这个数+1,x+1不变,就可以让逆序对少1。如果x在x+1后面,我们就认为连边(x+1,x),x也有可能与x-1连边,形成一个长度为L的链,那减少的逆序对数量就是L/2
代码:
//还是自己菜最后还是看了网上模板才写出来的#include <bits/stdc++.h>#define LL long long
using namespace std;const int N=3e6+10;
LL num[N],a[N];
LL ans;
void Merge(int l,int mid,int r) //分治的治 合并是求逆序对的关键
{int i=l,j=mid+1,k=l;while(i<=mid&&j<=r){if(num[i]>num[j]) //前半部分中比num[i]大的数都比num[j]大,将num[j]放在num[i]前面的话,逆序数要加上mid+1-i{a[k++]=num[j++];ans+=mid-i+1; //统计逆序对}else //这里这情况不产生逆序对a[k++]=num[i++];}while(i<=mid)a[k++]=num[i++];while(j<=r)a[k++]=num[j++];for(int e=l;e<=r;e++) //将这次操作完的num数组更新num[e]=a[e];
}void Merge_sort(int l,int r) //分治的分 在这里不断地把一个串细分然后回溯合并
{if(l<r){int mid=(l+r)/2;Merge_sort(l,mid);Merge_sort(mid+1,r);Merge(l,mid,r);}
}
int vis[N];
int main()
{int n;cin>>n;int tot=0;for(int i=0;i<n;i++){cin>>num[i];if(vis[num[i]+1]){tot++;}else vis[num[i]]=1;}ans=0;Merge_sort(0,n-1); //cout<<ans<<endl;cout<<ans-tot;return 0;
}
/*
8
8 1 6 3 4 5 2 7
*/