zoukankan      html  css  js  c++  java
  • NOIP2013提高组 T2 火柴排队

    一开始看也想不到这居然要用到逆序对,归并排序。

    先来看看题目:

    涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度。 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为: ∑(ai-bi)^2

    其中 ai 表示第一列火柴中第 i 个火柴的高度,bi 表示第二列火柴中第 i 个火柴的高度。

    每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对 99,999,997 取模的结果。

    样例输入:

    4
    1 3 4 2
    1 7 2 4

    样例输出:

    2

      根据样例,设第二行的数为a{1,3,4,2},第三行的数为b{1,7,2,4}。对于题目要求通过交换使得两列火柴之间的的距离最小,满足这个要求只能使a中高度最小的火柴和b中高度最小的火柴搭配,第二小的和第二小的搭配。为了方便处理和后续的操作,把a和b进行离散化。离散化后,a{1,3,4,2},b{1,4,2,3}(离散化详解在*1)。遍历数组a,查找a[i]在数组b中所对应的位置(详细处理在*2)(需要用二分查找*3),存入新数组R,处理后为R{1,4,2,3},R[i]即为a[i]将要移到的位置,最小交换的次数正是R的逆序对数量。a中的3要移到R中3的位置,需要向右交换两次。相同的,可以这样认为,R中的3要向左移到a中的3的位置,则需要两次交换。R中3(即R[4])的逆序对数量为2,整个R的逆序对数量也为2。所求最少交换次数就是R的逆序对数量。使用归并排序。

      时间复杂度(大概):O(7*(n log n))  离散化:4*(n log n) ( 4次快排)  预处理二分查找+二分查找:2*(n log n)  归并排序:(n log n)  绝对不会超时qwq 

    *1:离散化前:a{1,3,4,2},b{1,7,2,4},给每个数组的每一个数标上序号,按照数组内容带上序号一起排序,重新编号,再根据之前标上的序号排回来恢复原状。

    原始状态:

    a 1 3 4 2
    序号 1 2 3 4
    b 1 7 2 4
    序号 1 2 3 4

    按照数组内容排序:

    a 1 2 3 4
    序号 1 4 2 3
    b 1 2 4 7
    序号 1 3 4 2

    重新编号:

    a 1 2 3 4
    序号 1 4 2 3
    b 1 2 3 4
    序号 1 3 4 2

    按照序号重新排序恢复:

    a 1 3 4 2
    序号 1 2 3 4
    b 1 4 2 3
    序号 1 2 3 4

    完成,a离散化后和原来一样是因为样例特殊,参考b的离散化过程就好了。

    *2:a[i]在数组b中所对应的位置。首先列出数组。

    a 1 3 4 2
    b 1 4 2 3
    序号 1 2 3 4
    R        

    i=1的情况:a[i]为1,b中的1在b[1]中,b[1]对应的序号为1,所以R[i]为1,i=1,所以R[1]填上1。

    i=2的情况:a[i]=3,b[4]=3,所以b中的3在b[4],对应序号为4。R[2]填上4

    i=3:a[i]=4,b[2]=4,所以R[i]=2,R[3]填上2

    i=4:a[i]=2,b[3]=2,所以R[4]=3

    最终得R为:

    R 1 4 2 3

    *3:如果查找a[i]在数组b中所对应的位置使用两重循环,则查找的时间复杂度为O(n^2),数据范围为n<=100000,光是查找就会超时,所以需要用二分排序。

    贴上代码详细参考:

      1 type
      2         arr=array[0..100000] of longint;
      3 var
      4         a1,b1,a,r:arr;
      5         n,i,j:longint;
      6         left,right,mid:longint;
      7         ans:qword;
      8 procedure qsort(var a,b:arr);  //快排a数组,捆绑b数组
      9     procedure sort(l,r: longint);
     10       var
     11          i,j,x,y: longint;
     12       begin
     13          i:=l;
     14          j:=r;
     15          x:=a[(l+r) div 2];
     16          repeat
     17            while a[i]<x do
     18             inc(i);
     19            while x<a[j] do
     20             dec(j);
     21            if not(i>j) then
     22              begin
     23                 y:=a[i];
     24                 a[i]:=a[j];
     25                 a[j]:=y;
     26                 y:=b[i];
     27                 b[i]:=b[j];
     28                 b[j]:=y;
     29                 inc(i);
     30                 dec(j);
     31              end;
     32          until i>j;
     33          if l<j then
     34            sort(l,j);
     35          if i<r then
     36            sort(i,r);
     37       end;
     38     begin
     39        sort(1,n);
     40     end;
     41 procedure mergesort(s,t:longint);  //归并排序用来统计逆序对
     42 var
     43         mid,i,j,k:longint;
     44 begin
     45         if s=t then exit;
     46         mid:=(s+t) div 2;
     47         mergesort(s,mid);
     48         mergesort(mid+1,t);
     49         i:=s;
     50         j:=mid+1;
     51         k:=s;
     52         while (i<=mid) and (j<=t) do
     53                 if a[i]<=a[j] then
     54                 begin
     55                         r[k]:=a[i];
     56                         inc(i);
     57                         inc(k);
     58                 end
     59                 else
     60                 begin
     61                         r[k]:=a[j];
     62                         inc(j);
     63                         inc(k);
     64                         ans:=ans+(mid-i+1); //逆序对
     65                 end;
     66         while i<=mid do
     67         begin
     68                 r[k]:=a[i];
     69                 inc(i);
     70                 inc(k);
     71         end;
     72         while j<=t do
     73         begin
     74                 r[k]:=a[j];
     75                 inc(j);
     76                 inc(k);
     77         end;
     78         for i:=s to t do
     79                 a[i]:=r[i];
     80 end;
     81 begin
     82         assign(input,'match.in');
     83         assign(output,'match.out');
     84         reset(input);
     85         rewrite(output);
     86         readln(n);
     87         for i:=1 to n do
     88         begin
     89                 read(a1[i]);  //读入a数组
     90                 r[i]:=i;  //编号
     91         end;
     92         qsort(a1,r);  //按照数组内容排序
     93         for i:=1 to n do a1[i]:=i;  //重新编号   {离散化}
     94         qsort(r,a1);  //按照编号排序复原
     95         readln;
     96         for i:=1 to n do 
     97         begin
     98                 read(b1[i]);  //读入b数组
     99                 r[i]:=i;  //编号
    100         end;
    101         qsort(b1,r);  //按照数组内容排序
    102         for i:=1 to n do b1[i]:=i;  //重新编号   {离散化}
    103         qsort(r,b1);  //按照编号排序复原
    104 
    105         {for i:=1 to n do  //处理a[i]在数组b中所对应的位置,使用两重循环,n到达1000时就会超时,所以舍弃
    106                 for j:=1 to n do
    107                         if b1[i]=a1[j] then
    108                         begin
    109                                 a[i]:=j;
    110                                 break;
    111                         end;  }
    112 
    113         for i:=1 to n do r[i]:=i;
    114         qsort(a1,r);  //按照内容排序
    115         for i:=1 to n do  //遍历每个b[i]查找在a中的位置(这里a和b交换了,所以是查找b[i]在a中的位置)
    116         begin
    117                 left:=1;
    118                 right:=n;
    119                 mid:=(left+right) div 2;
    120                 while (a1[mid]<>b1[i]) and (left<=right) do  //二分查找,时间复杂度O(n log n)
    121                 begin
    122                         if a1[mid]>b1[i] then right:=mid-1
    123                         else left:=mid+1;
    124                         mid:=(left+right) div 2;
    125                 end;
    126                 a[i]:=r[mid]; //此处的a数组即为上面所讲的R数组
    127         end;
    128         ans:=0;
    129         fillchar(r,sizeof(r),0);
    130         mergesort(1,n);  //归并排序统计逆序对
    131         writeln(ans mod 99999997);  //依照题意对99999997取模
    132         close(input);
    133         close(output);
    134 end.
  • 相关阅读:
    su命令cannot set groups: Operation not permitted的解决方法
    Docker 使用指南 (二)—— 搭建本地仓库
    90后小伙云上打造倾诉社交平台
    一起用HTML5 canvas做一个简单又骚气的粒子引擎
    PCB设计流程
    PCB设计检查
    C语言——输入输出函数
    (1)STM32使用HAL库操作GPIO
    几个输入输出函数的总结
    STM32标准库GPIO操作
  • 原文地址:https://www.cnblogs.com/SJum/p/7412644.html
Copyright © 2011-2022 走看看