首页 > 编程语言 > 详细

区间翻转 归并排序 + 逆序对

时间:2020-09-07 17:28:33      阅读:119      评论:0      收藏:0      [点我收藏+]

区间翻转

这个题目如果不知道怎么用归并排序求逆序对还是很难想的,但是知道用归并排序求逆序对也不是一个很好写的题目。

注意题目是每一个数只出现一次!!!

思路:

整体求考虑每一次操作的影响。

因为每次操作都是2的幂次,那么我们先求出划分成\(2^x\) 块的每一个块内的逆序对之和,这个可以用归并排序做,所以假设 \(dp[x]\) 表示每一个块大小是 \(2^x\) 次方的所有块逆序对之和(注意这个定义是大小是\(2^x\) 块),那么容易知道,一个块的逆序对+顺序对=\(len*(len-1)/2\) 这个 \(len\) 表示块的大小。

接下来考虑如果要求划分成 $2^q $ 块,那么每块大小就是 \(2^x = 2^n - 2^q\) ,因为每块划分大小是 \(2^x\) 这样对更大的块和更小的块的影响是不同的,对比这个块更小的块的影响就是:顺序对变成逆序对,逆序对变成顺序对,对比这个块更大的块的影响是:变化的块顺序对逆序对交换,但是块与块直接的顺逆序对数量不变。

最后得出来的式子就是:\(f[i]\) 表示 \(2^i\) \(temp[i]\) 表示这次操作未更新之前的 \(dp[i]\)

\(i<=x\)\(dp[i] = f[i]*(f[i]-1)/2*f[n-i]-dp[i]\)

\(i>x\)\(dp[i] = dp[i]-temp[i-1]+dp[i-1]\)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 3e6+10;
ll a[maxn],temp[maxn],dp[40],f[40];
ll merge(int pos,int l,int r){
    if(pos==0){ dp[pos] = 0;return 0;}
    ll ans = 0;
    int mid = (l+r)>>1;
    ans += merge(pos-1,l,mid);
    ans += merge(pos-1,mid+1,r);
    int now = 0,x = l,y = mid + 1;
    while(x<=mid||y<=r){
        if(x<=mid&&y<=r) {
            if(a[x]<=a[y]) temp[++now]=a[x],x++;
            else temp[++now]=a[y],y++,ans+=mid-x+1;
        }
        else if(x<=mid) temp[++now] = a[x],x++;
        else if(y<=r) temp[++now] = a[y],y++;
    }
    dp[pos] += ans;
    for(int i=l,j=1;i<=r&&j<=now;i++,j++) a[i] = temp[j];
    return ans;
}

void init(){
    f[0] = 1;
    for(int i=1;i<=22;i++) f[i]=f[i-1]*2;
}
int main(){
    init();
    int n,m;
    scanf("%d%d",&n,&m);
    int len = 1<<n;
    for(int i=1;i<=len;i++) scanf("%lld",&a[i]);
    merge(n,1,len);
    while(m--){
        int x;
        scanf("%d",&x);
        x = n-x;
        for(int i=0;i<=n;i++) temp[i] = dp[i];
        for(int i=0;i<=x;i++) dp[i] = f[n-i]*f[i]*(f[i]-1)/2-dp[i];
        for(int i=x+1;i<=n;i++) dp[i] = dp[i] - temp[i-1] + dp[i-1];
        printf("%lld\n", dp[n]);
    }
    return 0;
}

区间翻转 归并排序 + 逆序对

原文:https://www.cnblogs.com/EchoZQN/p/13627703.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!