码迷,mamicode.com
首页 > 其他好文 > 详细

noip2013火柴排队_Solution

时间:2017-05-25 23:34:35      阅读:205      评论:0      收藏:0      [点我收藏+]

标签:++   print   sizeof   img   逆序   目的   逆序对   code   noip   

技术分享

 

 

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

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

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

最后目的是:对任意(aibi)和(aj-b-j),当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\n",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 */

 

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

 

noip2013火柴排队_Solution

标签:++   print   sizeof   img   逆序   目的   逆序对   code   noip   

原文地址:http://www.cnblogs.com/cmyg/p/6906139.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!