zoukankan      html  css  js  c++  java
  • 洛谷 P4375 [USACO18OPEN]Out of Sorts G(树状数组求冒泡排序循环次数加强版)

    传送门

    参考资料:

      [1]:https://www.cnblogs.com/Miracevin/p/9662350.html

      [2]:https://blog.csdn.net/lengxuenong/article/details/80482202?utm_source=blogxgwz1

      今天已经理解了一晚上了,还是处于懵懵懂懂的状态,明天在肝一天,一定要将自己理解的题解写出来,哇咔咔!

    题解

      定义数组 a;

      先将含有 n 个元素的数组 a 离散化,则离散化后的 n 个元素对应 1~n 的某个排列,而我们所要求的就是将离散化后的排列变为 1,2,3,...,n 所需的循环次数

      对于位置 i ,在这个双向排序过程中,每次 while( ) 循环会把一个 i 之前的大于 i 的数移到 i 后面,并且把一个 i 之后小于 i 的数移到 i 的前面

      for : i  1 to N

        我们可以对于所有的位置 i ,找到[1,i]范围内比 i 小的数的个数 s,i-s 就是 i 位置把小于 i 的放在 i 位置前面,大于 i 的放在 i 位置后面的循环次数。

    对红色字体的理解

      冒泡排序,通过交换相邻两数最终使得数组有序;

      对于每个位置 i ,如果比 i 大的数都交换到 i 位置之后,比 i 小的数都交换到 i 位置之前;

      那么,等结束最后一个 i 位置的时候,冒泡排序也就结束了,此时数组也就是有序的。

      因此,对于此题的双向循环,每次判断当前位置 i 需要通过多少次while( )循环才能使得:

      比 i 大的数都交换到 i 位置之后,比 i 小的数都交换到 i 位置之前;

      因此,只需要求出 [1,i] 位置上比 i 大的数的个数,输出最大的那个即是答案;

    •Code

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define lowbit(x) (x&(-x))
     4 const int maxn=1e5+50;
     5 
     6 int n;
     7 struct Node
     8 {
     9     int val;
    10     int id;
    11     int newVal;
    12 }a[maxn];
    13 //==================BIT=====================
    14 int bit[maxn];
    15 void Add(int x)
    16 {
    17     while(x <= n)
    18     {
    19         bit[x]++;
    20         x += lowbit(x);
    21     }
    22 }
    23 int Sum(int x)
    24 {
    25     int sum=0;
    26     while(x > 0)
    27     {
    28         sum += bit[x];
    29         x -= lowbit(x);
    30     }
    31     return sum;
    32 }
    33 //=======================================
    34 bool cmp(Node _a,Node _b) {//注意,如果val相同,初始编号 id 小的在前
    35     return _a.val < _b.val || (_a.val == _b.val && _a.id < _b.id);
    36 }
    37 bool cmp1(Node _a,Node _b){//将数组恢复到刚开始输入时的状态
    38     return _a.id < _b.id;
    39 }
    40 void Solve()
    41 {
    42     sort(a+1,a+n+1,cmp);//离散化
    43     for(int i=1;i <= n;++i)
    44         a[i].newVal=i;//存储离散化后的值
    45     sort(a+1,a+n+1,cmp1);
    46     int res=1;
    47     for(int i=1;i <= n;++i)
    48     {
    49         Add(a[i].newVal);
    50         res=max(res,i-Sum(i));//询问每个位置,找到所需的最大的循环次数
    51     }
    52     printf("%d
    ",res);
    53 }
    54 int main()
    55 {
    56     scanf("%d",&n);
    57     for(int i=1;i <= n;++i)
    58         scanf("%d",&a[i].val),a[i].id=i;
    59     Solve();
    60 }
    View Code

    •初始疑惑

      将 i 之前的大于 i 的数归位,貌似只用到了问题中的第一个for( ),而并没有用第二个 for( )循环啊;

      那为什么 i-s 就是 i 位置把小于 i 的放在 i 位置前面,大于 i 的放在 i 位置后面的循环次数呢?

    我的理解:

      ①如果将 [1,i] 位置中的大于 i 的数全部移到 i 位置后,[i+1,n]位置中的数肯定全部大于 i;

      如果 [i+1,n] 位置存在小于 i 的数,那,[1,i]中肯定存在大于 i 的数,不然,怎么交换呢?

      这样的话,[1,i]位置中大于 i 的数就没有全部移到 i 位置后,与条件①矛盾;

      所以条件①成立;


    分割线:2019.7.17

    •感想

      当初理解了好长时间的东西到如今成了自然而然地事;

    •Code

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define lowbit(x) (x&-x)
     4 const int maxn=1e5+50;
     5 
     6 int n;
     7 struct Data
     8 {
     9     int v;
    10     int id;
    11     int newV;
    12 }data[maxn];
    13 struct BIT
    14 {
    15     int bit[maxn];
    16     void Init()
    17     {
    18         memset(bit,0,sizeof(bit));
    19     }
    20     void add(int t)
    21     {
    22         while(t < maxn)
    23         {
    24             bit[t]++;
    25             t += lowbit(t);
    26         }
    27     }
    28     int Sum(int t)
    29     {
    30         int sum=0;
    31         while(t > 0)
    32         {
    33             sum += bit[t];
    34             t -= lowbit(t);
    35         }
    36         return sum;
    37     }
    38 }_bit;
    39 
    40 ///树状数组求逆序对时,v相同的一定要让编号小的在前
    41 bool cmp1(Data a,Data b)
    42 {
    43     if(a.v != b.v)
    44         return a.v < b.v;
    45     return a.id < b.id;
    46 }
    47 bool cmp2(Data a,Data b)
    48 {
    49     return a.id < b.id;
    50 }
    51 int Solve()
    52 {
    53     sort(data+1,data+n+1,cmp1);
    54     for(int i=1;i <= n;++i)
    55         data[i].newV=i;
    56     sort(data+1,data+n+1,cmp2);
    57 
    58     _bit.Init();
    59     int ans=1;
    60     for(int i=1;i <= n;++i)
    61     {
    62         _bit.add(data[i].newV);
    63         ans=max(ans,i-_bit.Sum(i));
    64     }
    65 
    66     return ans;
    67 }
    68 int main()
    69 {
    70 //    freopen("C:\Users\hyacinthLJP\Desktop\in&&out\contest","r",stdin);
    71     scanf("%d",&n);
    72     for(int i=1;i <= n;++i)
    73     {
    74         scanf("%d",&data[i].v);
    75         data[i].id=i;
    76     }
    77     printf("%d
    ",Solve());
    78 
    79     return 0;
    80 }
    View Code
  • 相关阅读:
    ssh 私匙登录, 文件rswrst权限
    从内存使用的角度来理解.Net底层架构
    (转)C#为什么要使用Invoke,它和BeginInvoke有什么区别
    如何通过微信自定义菜单跳转到自己的网站
    (转)HubbleDotNet+Mongodb 构建高性能搜索引擎--概述
    (转)HubbleDotNet 和 Lucene.net 性能对比测试
    C#异步提示和技巧
    关于System.Windows.Forms.DateTimePicker的一个Bug
    关于frameset中指定区域回退的实现
    java.lang.NoClassDefFoundError Adding a jar to an RCP application
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/9833481.html
Copyright © 2011-2022 走看看