• 【CZY选讲·逆序对】


    题目描述

    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被称为逆序对当且仅当iaj。

    数据范围

    n<=17,Q<=200000,1<=ai<=2^n。

    题解:        

             ①尝试将操作转化为可以记录翻转状态的形式

             ②找规律:

                                  对f[1]+f[2]+f[3]+f[4]+f[5]+f[6]+f[7]+f[8]进行2^3操作

                                 f[1]+f[2]+f[3]+f[4]+f[5]+f[6]+f[7]+f[8] 

                               =f[2]+f[1]+f[4]+f[3]+f[6]+f[5]+f[8]+f[7] 

                               =f[4]+f[3]+f[2]+f[1]+f[8]+f[7]+f[6]+f[5] 

                               =f[8]+f[7]+f[6]+f[5]+f[4]+f[3]+f[2]+f[1]

               ③然后每次2k操作转化为按照上述方式(认真观察上述方式)交换长度为21,22…2k子区间

               ④使用down[i]表示按照上述规律的翻转的长度为2i单位区间每一对之间的逆序对数之和。

                 ⑤使用up[i]表示按照上述规律的翻转的长度为2i单位区间每一对之间的顺序对数之和。

               ⑥使用f[i]表示当前区间是否被反转。

               ⑦每次询问处理:O(logn),小于k的区间就根据f[i]加,大于k的直接加

               ⑧初始化使用归并排序求出原先的总逆序对数同时初始化down,up,f

    #include <cmath>
    #include <cstdio>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <string>
    #include <cstring>
    #include <map>
    #include <vector>
    using namespace std;
    const int N=(1<<17)+5;
    long long st[N][20],ST[N][20];
    int p[N],i,sum,o,a[N],b[N],n,T,PP,now,j,A,RR[N];
    void gb(int l,int r)
    {
        if (l==r) return;
        int mid=(l+r)/2;
        gb(l,mid); gb(mid+1,r);
        int i=l,j=mid+1,o=l;
        for (i=l; i<=r; i++) b[i]=a[i];
        for (i=r; i>=mid; i--) {RR[i]=i; if (i!=r && b[i+1]==b[i]) RR[i]=RR[i+1];}
        i=l; j=mid+1;
        while (i<=mid && j<=r)
        {
            if (b[i]<=b[j]) {a[o++]=b[i];if (b[i]==b[j]) ST[l][p[r-l+1]]+=RR[j]-j+1; i++;} else
            {
                a[o++]=b[j]; st[l][p[r-l+1]]+=mid-i+1;
    
                j++;
            }
        }
        if (i<=mid) for (j=i; j<=mid; j++) a[o++]=b[j]; else
        if (j<=r) for (i=j; i<=r; i++) a[o++]=b[i];
    }
    long long t[105],TT[105];
    int main()
    {
        freopen("pair.in","r",stdin);
        freopen("pair.out","w",stdout);
        scanf("%d",&n);
        sum=(1<<n);
        for (i=1; i<=sum; i++) scanf("%d",&a[i]);
        for (i=1; i<=17; i++) p[1<<i]=i;
        gb(1,sum);
        scanf("%d",&T);
        for (i=1; i<=n; i++)
          for (j=1; j<=(1<<n); j+=(1<<i))
          {
              t[i]+=st[j][i];
              TT[i]+=ST[j][i];
          }
        long long ans=0;
        while (T--)
        {
            int Q;
            scanf("%d",&Q);
            for (i=1; i<=Q; i++) t[i]=1ll*(1<<i-1)*(1<<i-1)*(1<<n-i)-TT[i]-t[i];
            for (i=1; i<=n; i++) ans+=t[i];
            printf("%I64d
    ",ans); ans=0;
        }
        return 0;
    }//czy020202

     

    No need to doubt all my lost to faded glory,

    My soul is small but longs to roam.——————汪峰《Song Of Redemption》

  • 相关阅读:
    [JavaScript] 根据字符串宽度截取字符串
    [JavaScript] 时间戳格式化为yyyy-MM-dd日期
    [JavaScript] 获取昨日前天的日期
    [As3.0] 获取本机信息
    [CSS3] 几种分割线实现方法
    [JS] js 判断用户是否在浏览当前页面
    [JS] 理解jquery的$.extend()、$.fn和$.fn.extend()
    [JS] 屏蔽右键
    [JS] jq绑定事件的参数传递
    [CSS3] 各种角度的三角形绘制
  • 原文地址:https://www.cnblogs.com/Damitu/p/7654576.html
Copyright © 2020-2023  润新知