逆序对(归并排序)
作者:互联网
作为程序员的小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
->
第一次:1 2 3 4 -> 逆序对数为0
->
第二次:4 3 2 1 -> 逆序对数为6
->
第三次:4 3 2 1 -> 逆序对数为6
->
第四次: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