CodeForces 414 C.Mashmokh and Reverse Operation(归并排序)

本文介绍了一种算法,用于处理长度为2^n的序列,通过多次操作将序列分割并反转子序列,随后计算反转后的逆序对数量。利用归并排序的思想,在操作前后交换各层产生的逆序对数和顺序对数,从而高效地得出答案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description
给出一个长度为2^n的序列,m次操作,每次操作给出一整数q,把该序列分成连续的长度均为2^q的2^(n-q)段后,把每段反转,并查询反转后的逆序对
Input
第一行一整数n,之后一个长度为2^n的序列ai,然后输入一整数m表示操作数,之后m个整数qi表示一次操作
(0<=n<=20,1<=ai<=1e9,1<=m<=1e6,0<=qi<=n)
Output
对于每次操作,输出操作后序列的逆序对数
Sample Input
2
2 1 4 3
4
1 2 0 2
Sample Output
0
6
6
0
Solution
考虑归并排序求逆序对的过程,对于一个反转2^q子段的操作,反转后每段的逆序对数变成反转前的顺序对数,且段与段之间的逆序对数并没有改变,故在归并排序过程中统计每层产生的逆序对数和顺序对数,对于一个操作q,把所有长度不超过2^q的层产生逆序对数和顺序对数交换,更长的段保持不变,统计每层的逆序对数即为该次查询的答案
Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
#define maxn 1111111
ll cnt[22][2];//cnt[i][0]表示归并排序中长度为2^i的子段产生的逆序对,cnt[i][1]表示顺序对 
int n,a[maxn],b[maxn],m,q;
void Merge_Sort(int l,int r,int len)
{
    if(l>=r)return ;
    int mid=(l+r)/2;
    Merge_Sort(l,mid,len-1),Merge_Sort(mid+1,r,len-1);
    int i=l,j=mid+1,res=0;
    while(i<=mid&&j<=r)
    {
        if(a[i]<a[j])cnt[len][1]+=r-j+1,i++;
        else j++;
    } 
    i=l,j=mid+1;
    while(i<=mid&&j<=r)
    {
        if(a[i]>a[j])cnt[len][0]+=mid-i+1,b[res++]=a[j++];
        else b[res++]=a[i++];
    }
    while(i<=mid)b[res++]=a[i++];
    while(j<=r)b[res++]=a[j++];
    for(int i=l;i<=r;i++)a[i]=b[i-l];
}
int main()
{
    while(~scanf("%d",&n))
    {
        memset(cnt,0,sizeof(cnt));
        for(int i=1;i<=(1<<n);i++)scanf("%d",&a[i]);
        Merge_Sort(1,1<<n,n);
        scanf("%d",&m);
        while(m--)
        {
            scanf("%d",&q);
            ll ans=0;
            for(int i=1;i<=n;i++)
            {
                if(i<=q)swap(cnt[i][0],cnt[i][1]);
                ans+=cnt[i][0];
            }
            printf("%I64d\n",ans);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值