其他分享
首页 > 其他分享> > 逆序对(归并排序)

逆序对(归并排序)

作者:互联网

作为程序员的小Q,他的数列和其他人的不太一样,他有个数。

老板问了小Q一共 m次,每次给出一个整数, 要求小Q把这些数每分为一组,然后把每组进行翻转,小Q想知道每次操作后整个序列中的逆序对个数是多少呢?  
输入描述:
第一行一个数

第二行
个数,表示初始的序列(
)
第三行一个数

第四行m个数表示

输出描述:
m行每行一个数表示答案。

输入例子1:
2
2 1 4 3
4
1 2 0 2

输出例子1:
0
6
6
0

例子说明1:
初始序列2 1 4 3
2^{q_1} = 2
 ->
第一次:1 2 3 4 -> 逆序对数为0
2^{q_2} = 4
 ->
第二次:4 3 2 1 -> 逆序对数为6
2^{q_3} = 1
 ->
第三次:4 3 2 1 -> 逆序对数为6
2^{q_4} = 4
 ->
第四次:1 2 3 4 -> 逆序对数为0


这道题目一眼看上去就是归并排序,但是序列可以翻转,我们就要想到逆序对的一个特点:逆序对=总数-有序对。

我们先记录每一层有多少个逆序对,并且可以发现一个规律:上层数不受下层影响,但是下层数受到上层数影响,于是我们可以先预处理所有数的逆序对,每一次询问只用改变下层数的值,然后统计求和,时间复杂度为O(n*2^n+nm)。

代码如下:
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int MAXN=(1<<20)+5;
ll n,nn,m,a[MAXN],b[MAXN],f[25],z[25],c[MAXN];
void msort(ll a[],ll l,ll r,ll d,ll g[])
{
    if(l>=r)
        return ;
    int mid=l+r>>1;
    msort(a,l,mid,d-1,g);
    msort(a,mid+1,r,d-1,g);
    ll i=l,j=mid+1,k=l;
    while(i<=mid&&j<=r)
    {
        if(a[i]<a[j])
            b[k++]=a[i++];
        else if(a[i]==a[j])
            b[k++]=a[i++];
        else
            b[k++]=a[j++],g[d]+=mid-i+1;
    }
    while(i<=mid)
        b[k++]=a[i++];
    while(j<=r)
        b[k++]=a[j++];
    for(i=l;i<=r;i++)
        a[i]=b[i];
}
int main()
{
    ios::sync_with_stdio(0),cin.tie(0);
    int i,j,q,x;
    cin>>n;
    nn=1<<n;
    for(i=1;i<=nn;i++)
        cin>>a[i],c[i]=a[i];
    msort(a,1,nn,n,f);
    reverse(c+1,c+nn+1);
    msort(c,1,nn,n,z);
    cin>>q;
    while(q--)
    {
        cin>>x;
        ll sum=0;
        for(i=x;i>=1;i--)
            swap(f[i],z[i]);
        for(i=1;i<=n;i++)
            sum=sum+f[i];
        cout<<sum<<endl;
    }
    return 0;
}

  

标签:归并,nn,ll,mid,msort,对数,排序,逆序
来源: https://www.cnblogs.com/siyue2903616750/p/14347510.html