BZOJ 2058 [Usaco2010 Nov]Cow Photographs:逆序对【环上最小逆序对】

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2058

题意:

  给你一个由1~n组成的排列,首尾相接围成一个环。

  你可以任意次交换其中两个相邻位置的数字。

  最终你要让所有数字顺时针递增,只有n顺时针紧邻着1。

  问你最小的交换次数。

 

题解:

  举个例子。

  有一个由1~5组成的环:2 3 1 4 5

  对于这个环,最终答案有若干种情况:

    (1)1 2 3 4 5

    (2)2 3 4 5 1

    (3)3 4 5 1 2

    (4)4 5 1 2 3

    (5)5 1 2 3 4

  每一次变化,无非是分别将1~4移到了最右边。

  对于从(1)到(2)的变化,其实就是将原环中的1改为了一个比其他都大的数字(比如6),然后求了一遍逆序对。

  对应到最终结果中,也就是1变成了最右边的数。

 

  所以变化之后的答案 = 上一次的答案 - 数字i所贡献的逆序对个数 + 改成的更大的数所贡献的逆序对个数

 

  对于每一次将数字i改为更大的数时,i一定是当前环中最小的数字。

  令pos[i]为数字i在原环中出现的位置(1 <= pos <= n)。

  所以:

    i贡献的逆序对 = pos[i] - 1

    更大的数贡献的逆序对 = n - pos[i]

  即:res = res - 2*pos[i] + 1 + n

  

  对于所有res取最小即可。

 

AC Code:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #define MAX_N 100005
 5 #define INF 1000000000
 6 
 7 using namespace std;
 8 
 9 int n;
10 int a[MAX_N];
11 int l[MAX_N];
12 int r[MAX_N];
13 int dat[MAX_N];
14 int pos[MAX_N];
15 long long ans=0;
16 long long res=0;
17 
18 void read()
19 {
20     cin>>n;
21     for(int i=1;i<=n;i++)
22     {
23         cin>>a[i];
24         pos[a[i]]=i;
25     }
26 }
27 
28 void merge(int lef,int mid,int rig)
29 {
30     int n1=mid-lef+1;
31     int n2=rig-mid;
32     for(int i=0;i<n1;i++) l[i]=a[lef+i];
33     for(int i=0;i<n2;i++) r[i]=a[mid+i+1];
34     l[n1]=INF;
35     r[n2]=INF;
36     for(int i=0,j=0,k=lef;k<=rig;k++)
37     {
38         if(l[i]<r[j]) a[k]=l[i++];
39         else
40         {
41             a[k]=r[j++];
42             res+=n1-i;
43         }
44     }
45 }
46 
47 void merge_sort(int lef,int rig)
48 {
49     if(lef==rig) return;
50     int mid=(lef+rig)/2;
51     merge_sort(lef,mid);
52     merge_sort(mid+1,rig);
53     merge(lef,mid,rig);
54 }
55 
56 void solve()
57 {
58     merge_sort(1,n);
59     ans=res;
60     for(int i=1;i<n;i++)
61     {
62         res=res-2*pos[i]+1+n;
63         ans=min(ans,res);
64     }
65 }
66 
67 void print()
68 {
69     cout<<ans<<endl;
70 }
71 
72 int main()
73 {
74     read();
75     solve();
76     print();
77 }

 

posted @ 2017-10-21 12:34  Leohh  阅读(238)  评论(0编辑  收藏  举报