猫猫 TOM 和小老鼠 JERRY 最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。
最近,TOM 老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中 a i > a j a_i>a_j ai>aj 且 i < j i
Update:数据已加强。
第一行,一个数 n n n,表示序列中有 n n n个数。
第二行 n n n 个数,表示给定的序列。序列中每个数字不超过 1 0 9 10^9 109。
输出序列中逆序对的数目。
6
5 4 2 6 3 1
11
对于 25 % 25\% 25% 的数据, n ≤ 2500 n \leq 2500 n≤2500
对于 50 % 50\% 50% 的数据, n ≤ 4 × 1 0 4 n \leq 4 \times 10^4 n≤4×104。
对于所有数据, n ≤ 5 × 1 0 5 n \leq 5 \times 10^5 n≤5×105
请使用较快的输入输出
应该不会 O ( n 2 ) O(n^2) O(n2) 过 50 万吧 by chen_zhe
题目要求数列中逆序对的数量,比如2 1就是一对逆序对。
最简单的方法,在归并排序中,逆序对的数量就是 mid-p+1。
#include
#define int long long
using namespace std;
const int N=1e6+5;
int a[N],help[N];
int ans;
void merge_sort(int l,int r)
{
if(l<r)
{
int mid=(l+r)/2;
merge_sort(l,mid);
merge_sort(mid+1,r);
int k=l;
int p=l;
int q=mid+1;
while(p<=mid&&q<=r)
{
if(a[p]<=a[q])
//等于的时候ans不应该更新,所以这边条件一定要加等号
{
help[k++]=a[p++];
}
else{
ans+=mid-p+1;//只有完全大于的时候ans才需要更新
help[k++]=a[q++];
}
}
while(p<=mid) help[k++]=a[p++];
while(q<=r) help[k++]=a[q++];
for(int i=l;i<=r;i++)
a[i]=help[i];
}
}
signed main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
merge_sort(1,n);
cout<<ans;
}
数据规模过大,达10e9,所以使用结构体来存放,定义结构体存放数据的值val和数据的编号id。
使用sort函数排序,排序之后val是降序的,id是无序的,这时候只需要遍历id,将id依次放入树状数组,读取比id小的值的数量,这些数量相加就是逆序对的数量。
#include
#include
#define lowbits(x) x&(-x)
#define int long long
using namespace std;
const int N=1e6+5;
struct node{
int id,val;
}tr[N];
int n;
int tree[N];
bool cmp(node x,node y)
{
if(x.val==y.val) return x.id>y.id;
return x.val>y.val;
}
void updata(int x,int y)
{
for(int i=x;i<=n;i+=lowbits(i))
{
tree[i]+=y;
}
}
int query(int x)
{
int sum=0;
while(x)
{
sum+=tree[x];
x-=lowbits(x);
}
return sum;
}
signed main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>tr[i].val;
tr[i].id=i;
}
sort(tr+1,tr+1+n,cmp);
int ans=0;
for(int i=1;i<=n;i++)
{
updata(tr[i].id,1);
ans+=query(tr[i].id-1);
}
cout<<ans;
}
想法和树状数组一样,先把线段树的值初始化为0,接着依次修改id的在线段树中值为1,只需要统计小于id的数量就可以了
#include
#include
#define int long long
using namespace std;
const int N=1e6+5;
struct node{
int l,r,val;
}tr[N*4];
struct node2{
int id,val;
}a[N];
int n;
bool cmp(node2 x,node2 y)
{
if(x.val==y.val) return x.id>y.id;
return x.val>y.val;
}
void pushup(int u)
{
tr[u].val=tr[u*2].val+tr[u*2+1].val;
}
void build(int u,int l,int r)
{
if(l==r){
tr[u]={l,r,0};//线段树初始化为0
return ;
}
int mid=(l+r)/2;
build(u*2,l,mid);
build(u*2+1,mid+1,r);
tr[u]={l,r};
pushup(u);
}
void modify(int u,int x,int k)
{
if(tr[u].l==tr[u].r)
{
tr[u].val+=k;
return ;
}
int mid=(tr[u].l+tr[u].r)/2;
if(x<=mid) modify(u*2,x,k);
else modify(u*2+1,x,k);
pushup(u);
}
int query(int u,int l,int r)
{
if(l>tr[u].r||r<tr[u].l) return 0;
if(tr[u].r<=r&&tr[u].l>=l) return tr[u].val;
return query(u * 2, l, r)+query(u * 2 + 1, l, r);
}
signed main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i].val,a[i].id=i;
sort(a+1,a+1+n,cmp);
build(1,1,n);
int ans=0;
for(int i=1;i<=n;i++)
{
modify(1,a[i].id,1);//修改值为1
ans+=query(1,1,a[i].id-1);
}
cout<<ans<<endl;
}