• noip2013火柴排队_Solution


    要想对任意(aibi)和(aj),当ai<aj时,都有bi<=bj;当ai>=aj,bi>=bj,当对a进行升序排序后(b同时发生改变,从而不改变值,最后有a1<=a2<=…<=an),必须满足b1<=b2<=…<=b­n

    否则,必存在(aibi)和(aj),有ai<ajbi>bj,交换aiaj后,(aj*bi+ ai*bj)-( ai*bi+ aj*bj)=(aj-ai)*( bi-bj)>0,数值更小,即不是所满足的序列。

    唯有满足条件“对任意(aibi)和(aj),当ai<aj时,都有bi<=bj;当ai>=aj,bi>=bj”的序列才是值最小的序列。

    最后目的是:对任意(aibi)和(aj),当ai<aj时,都有bi<=bj;当ai>=aj,bi>=bj,其中题目限制“同一列火柴的高度互不相同”,所以对a,b序列进行从小到大排序,数的编号具有唯一性,即最后a,b两个序列中,aia序列的编号等于bib序列的编号。

    每一次操作,一列(a,b数组)中相邻的两个数进行交换,其中aiai+1的交换等效于bibi+1的交换。我们可以固定a序列不动,修改b序列,最优的操作满足操作次数最少。

    b序列第i位的数要移到目标位置第vi位中,求出v序列。b序列的数的移动顺序是按照对应的v序列的数从小到大。当目标位置为第vi位对应的bi(原来)需要移动时,前面的第1~vi-1位已经排好,而其它bi(原来)前面的数为还未移动的数,即对应的v序列的值大于vi。所以bi(原来)需要向左移动的次数为满足j<i and vj>vi所有的j的个数。

    即总的操作次数为v序列的逆序对的个数。有两种方法求逆序对使得时间复杂度为O(nlogn):

    1.归并排序+统计

    2.离散化+树状数组

    Code:

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <math.h>
      4 #define yu 99999997
      5 #define maxn 100000
      6  
      7 struct node
      8 {
      9     long value,pos;
     10 }a[maxn+1],b[maxn+1];
     11 long v[maxn+1],t[maxn+1],ans;
     12  
     13 int cmp(const void *a,const void *b)
     14 {
     15     if ((*(struct node *)a).value<(*(struct node *)b).value)
     16         return -1;
     17     else
     18         return 1;
     19 }
     20  
     21 void mergesort(long l,long r)
     22 {
     23     if (l==r)
     24         return ;
     25     long mid,x,y,z,i;
     26     mid=(l+r)/2;
     27     mergesort(l,mid);
     28     mergesort(mid+1,r);
     29     for (i=l;i<=r;i++)
     30         t[i]=v[i];
     31     x=l;
     32     y=mid+1;
     33     z=l;
     34     while (x<=mid && y<=r)
     35     {
     36         //两个数相等时让左边的数先加,因为相同的数不能凑成一对
     37         if (t[x]<=t[y])
     38         {
     39             v[z]=t[x];
     40             x++;
     41             //v[x] > v[mid+1]~v[y-1]
     42             ans=(ans+(y-mid-1))%yu;
     43         }
     44         else if (t[x]>t[y])
     45         {
     46             v[z]=t[y];
     47             y++;
     48         }
     49         z++;
     50     }
     51     if (x<=mid)
     52     {
     53         //v[x] > v[mid+1]~v[r]
     54         ans=(ans+(mid-x+1)*(r-mid))%yu;
     55         while (z<=r)
     56         {
     57             v[z]=t[x];
     58             x++;
     59             z++;
     60         }
     61     }
     62     else
     63     {
     64         while (z<=r)
     65         {
     66             v[z]=t[y];
     67             y++;
     68             z++;
     69         }
     70     }
     71 }
     72  
     73 int main()
     74 {
     75     long n,i;
     76     scanf("%ld",&n);
     77     for (i=1;i<=n;i++)
     78     {
     79         scanf("%ld",&a[i].value);
     80         a[i].pos=i;
     81     }
     82     for (i=1;i<=n;i++)
     83     {
     84         scanf("%ld",&b[i].value);
     85         b[i].pos=i;
     86     }
     87     qsort(a+1,n,sizeof(struct node),cmp);
     88     qsort(b+1,n,sizeof(struct node),cmp);
     89     for (i=1;i<=n;i++)
     90         v[b[i].pos]=a[i].pos;
     91     ans=0;
     92     mergesort(1,n);
     93     printf("%ld
    ",ans);
     94     return 0;
     95 }
     96 /*
     97 Input:
     98 10
     99 10 1 5 2 7 4 9 3 6 8
    100 7 5 1 8 10 4 6 2 3 9
    101 Output:
    102 18
    103 */

    感慨一下:想当初比赛做这道题,没有想到是逆序对,最终没有做出来,留下遗憾。现在终于写了个题解,把这道题做了,算是对遗憾的一种弥补吧。
    希望自己可以走得更远……

  • 相关阅读:
    第十二周作业
    2019春总结作业
    第一次实验总结
    第二次实验总结
    第十二周
    第十一周作业
    第九周作业
    第八周作业
    第七周作业
    第六周作业
  • 原文地址:https://www.cnblogs.com/cmyg/p/6906139.html
Copyright © 2020-2023  润新知