zoukankan      html  css  js  c++  java
  • codeforces 540E"Infinite Inversions"

    传送门

    题意:

      给你一个无限大的整数序列  p = {1, 2, 3, ...};

      有 n 次操作,每次操作交换第 ai 个数和第 aj 个数;

      求序列中逆序对的个数;

    题解:

      考虑交换完后的序列,存在连续的区间 [ i , j ] 使得 p[ i ] = i , 那么分下一下这种区间的特点

      假设 i 之前有 x 个数大于 p[ i ],那么可知对于第 i 个数有 x 个逆序对,同理,因为 p[ i+1 ] = p[ i ]

      所以 i+1 之前也一定有且只有 x 个数大于 p[ i+1 ],那么第 i+1 个数也有 x 个逆序对,那么对于连续的区间[i,j]

      易的区间 [ i , j ] 与其之前的数可构成的逆序对的个数为 (j-i+1)*x 个,那么可将其映射为一个值 i ,并记录其有 (j-i+1) 个数;

      例如,假设 n 次操作为

      1  4

      1  8

      那么交换完后,前 8 个数的排列状况为:

      1  2  3  4  5  6  7  8

      8  2  3  1  5  6  7  4

      那么可得区间 [2,3] 和区间[5,6]的值未发生改变,当然区间[9,+∞]也为发生改变,但[9,+∞]并不影响答案,所以不用考虑。

      那么根据之前提到的,将为改变的大区间映射到某个值身上,并记录有多少数映射到这个值上了,如下所示:

      1  2  3  4  5

      8  2  1  5  4

      映射完后,区间[2,3]合并到了2上,区间[5,7]合并到了5上,接下来就是求映射完后的数组的逆序对总个数,这就变成了经典的

      树状数组求逆序对个数的题了。

      这就完事了么????当然不是~~~

      考虑 4 这个值,其之前的 5 只给 4 提供了一个逆序对,但实际上 6,7 也会提供,那么这就少算了两个逆序对数,这该怎么办呢?

      考虑某个区间 [i , j],一共有 j-i+1 个数,易得区间 [ i , j ] 只会影响其之后且值小于 i 的数,那么就再用一次树状数组,如果来到了某个

      映射的值,那么将 i 之后的数通过树状数组 +(j-i),对于某个在其之后且值小于 i 的数 x ,直接在答案上额外加上 Sum(x+1)即可。

    AC代码:

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<map>
      5 #include<algorithm>
      6 using namespace std;
      7 #define lowbit(x) (x&-x)
      8 #define ll long long
      9 #define mem(a,b) memset(a,b,sizeof(a))
     10 const int maxn=1e6+50;
     11 
     12 int n;
     13 map<int,int>f;//记录交换后的序列状况
     14 int diff[maxn];
     15 int sum[maxn];
     16 struct Date
     17 {
     18     int val;
     19     int id;//初始编号
     20     int tot;//如果某个区间映射到值val上,那么tot记录的就是区间的总个数
     21     int newVal;//离散后的值
     22     Date(int val=0,int id=0,int tot=0):val(val),id(id),tot(tot){}
     23 }_date[maxn];
     24 
     25 struct BIT
     26 {
     27     int bit[maxn];
     28     void Init()
     29     {
     30         mem(bit,0);
     31     }
     32     void Add(int t,int x,int k)
     33     {
     34         while(t <= k)
     35         {
     36             bit[t] += x;
     37             t += lowbit(t);
     38         }
     39     }
     40     int Sum(int t)
     41     {
     42         int sum=0;
     43         while(t > 0)
     44         {
     45             sum += bit[t];
     46             t -= lowbit(t);
     47         }
     48         return sum;
     49     }
     50 }_bit;
     51 
     52 bool cmp1(Date a,Date b)
     53 {
     54     return a.val < b.val;
     55 }
     56 bool cmp2(Date a,Date b)
     57 {
     58     return a.id < b.id;
     59 }
     60 
     61 int Trans()
     62 {
     63     map<int,int>::iterator it;
     64     int index=0;
     65     int preIndex=f.begin()->first;
     66     int nexIndex;
     67 
     68     for(it=++f.begin();it != f.end();++it)
     69     {
     70         _date[++index]=Date(f[preIndex],index,1);
     71         nexIndex=it->first;
     72 
     73         //判断是否为未改变的区间
     74         int tot=nexIndex-preIndex-1;
     75         if(tot >= 1)
     76             _date[++index]=Date(preIndex+1,index,tot);
     77             
     78         preIndex=nexIndex;
     79     }
     80     _date[++index]=Date(f[preIndex],index,1);
     81 
     82     sort(_date+1,_date+index+1,cmp1);//按其val由小到大排序,方便离散化
     83     for(int i=1;i <= index;++i)
     84         _date[i].newVal=i;//离散化
     85     sort(_date+1,_date+index+1,cmp2);//按 id 从小到大复原
     86 
     87     return index;
     88 }
     89 
     90 ll Solve()
     91 {
     92     //离散化
     93     int index=Trans();
     94     _bit.Init();//树状数组初始化
     95     ll ans=0;
     96 
     97     //经典树状数组求逆序对个数
     98     for(int i=1;i <= index;++i)
     99     {
    100         int x=_date[i].newVal;
    101         _bit.Add(x,1,index);
    102         ans += 1ll*(i-_bit.Sum(x))*_date[i].tot;
    103     }
    104 
    105     //求解区间少加的逆序对个数
    106     _bit.Init();
    107     for(int i=1;i <= index;++i)
    108     {
    109         int x=_date[i].newVal;
    110         _bit.Add(x,_date[i].tot-1,index);//只有 tot > 1才会加入到树状数组中
    111 
    112         //求解 i 前值 > x 的未改变的区间少加的数的总个数
    113         if(_date[i].tot == 1)
    114             ans += _bit.Sum(index)-_bit.Sum(x);
    115 
    116     }
    117 
    118     return ans;
    119 }
    120 int main()
    121 {
    122 //    freopen("C:/Users/hyacinthLJP/Desktop/stdin/contest","r",stdin);
    123     scanf("%d",&n);
    124     for(int i=1;i <= n;++i)
    125     {
    126         int a,b;
    127         scanf("%d%d",&a,&b);
    128         int x,y;
    129         x=(!f.count(a) ? a:f[a]);
    130         y=(!f.count(b) ? b:f[b]);
    131 
    132         f[a]=y;
    133         f[b]=x;
    134     }
    135     printf("%I64d
    ",Solve());
    136 
    137     return 0;
    138 }
    View Code
  • 相关阅读:
    js 递归获取多层树的某个节点
    layui table 打印表格
    tp6 使用queue
    url带参数生成二维码
    redis的常用配置
    《TensorFlow实战》中AlexNet卷积神经网络的训练中
    JavaScript之闭包
    JavaScript之map与parseInt的陷阱
    JavaScript方法中this关键字使用注意
    什么是深度学习?
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/10502978.html
Copyright © 2011-2022 走看看