zoukankan      html  css  js  c++  java
  • 清北学堂模拟赛d2t3 逆序对(pair)

    题目描述
    LYK最近在研究逆序对。
    这个问题是这样的。
    一开始LYK有一个2^n长度的数组ai。
    LYK有Q次操作,每次操作都有一个参数k。表示每连续2^k长度作为一个小组。假设n=4,k=2,则a[1],a[2],a[3],a[4]为一个小组,a[5],a[6],a[7],a[8]为一个小组,a[9],a[10],a[11],a[12]为一个小组,a[13],a[14],a[15],a[16]也为一个小组。
    然后LYK对于每个小组都翻转,也就是说原数组会变成a[4],a[3],a[2],a[1],a[8],a[7],a[6],a[5],a[12],a[11],a[10],a[9],a[16],a[15],a[14],a[13]。之后它想求出这2^n个数的逆序对是多少。
    因此你需要输出对于每次操作,操作完后这2^n个数的逆序对有多少对。
    两个数ai,aj被称为逆序对当且仅当i<j且ai>aj。

    输入格式(pair.in)
    第一行一个数n。
    接下来一行2^n个数ai表示一开始的数组。
    接下来一行一个数Q,表示操作的次数。
    接下来一行Q个数,表示每次操作的参数k。

    输出格式(pair.out)
    Q行,表示每次操作后的答案。

    输入样例
    2
    2 1 4 3
    4
    1 2 0 2

    输出样例
    0
    6
    6
    0

    样例解释
    第一次操作,{2,1,4,3}->{1,2,3,4}
    第二次操作,{1,2,3,4}->{4,3,2,1}
    第三次操作,{4,3,2,1}->{4,3,2,1}
    第四次操作,{4,3,2,1}->{1,2,3,4}

    对于30%的数据n<=10,Q<=10。
    对于50%的数据n<=10,Q<=1000。
    对于80%的数据n<=10,Q<=200000。
    对于100%的数据n<=17,Q<=200000,1<=ai<=2^n。

    分析:比较巧妙的一道题。每次翻转操作其实就是将一个区间的逆序对个数与顺序对个数交换,那么先用归并排序求出逆序对的同时求出顺序对。接下来可以把翻转操作进行分解:假设交换翻转1234

    1,2,3,4 ---> 1,2  3,4 ---> 3,4 1,2 --->4,3,2,1.对每一个子区间的逆序对进行分析,可以知道每个元素的贡献是这个元素在区间长度为1的逆序对数+区间长度为2的逆序对数+区间长度为4的逆序数......

    每次修改操作只是更改了长度小于等于2^k的区间的逆序对数,对于长度大于2^k的区间就不用修改了.统计的时候把各个长度的区间答案加起来就是了.

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    long long n, a[(1 << 17) + 10],q,cnt[(1 << 17) + 10][2],b[(1 << 17) + 10],k;
    long long ans;
    
    void Sort(int l, int r, int dep)
    {
        if (l >= r)
            return;
        int mid = (l + r) >> 1;
        Sort(l, mid, dep - 1);
        Sort(mid + 1, r, dep - 1);
        int i = l, j = mid + 1, res = 0;
        while (i <= mid && j <= r)
        {
            if (a[i] < a[j])
            {
                cnt[dep][1] += r - j + 1;
                i++;
            }
            else
                j++;
        }
        i = l, j = mid + 1;
        while (i <= mid && j <= r)
        {
            if (a[i] > a[j])
            {
                cnt[dep][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 + 1];
    }
    
    int main()
    {
        scanf("%lld", &n);
        for (int i = 1; i <= (1 << n); i++)
            scanf("%lld", &a[i]);
        Sort(1, 1 << n, n);
        scanf("%lld", &q);
        while (q--)
        {
            scanf("%lld", &k);
            ans = 0;
            for (int i = 1; i <= n; i++)
            {
                if (i <= k)
                    swap(cnt[i][0], cnt[i][1]);
                ans += cnt[i][0];
            }
            printf("%lld
    ", ans);
        }
    
        return 0;
    }
  • 相关阅读:
    增强iOS应用程序性能的提示和技巧(25个)
    [iOS]用instancetype代替id作返回类型有什么好处?
    把cygwin加入右键菜单
    NSRange
    Centos7下安装MySQL
    (转)php 操作redis全部方法。
    unbuntu 安装php5.6
    unbuntu 安装nginx
    unbuntu 安装MySQL
    Ubuntu16.04下实现MySQL主从复制
  • 原文地址:https://www.cnblogs.com/zbtrs/p/7624829.html
Copyright © 2011-2022 走看看