zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    SDN2017 第四次作业
    SDN2017 第三次实验作业
    软件工程实践2017 个人作业——软件工程实践总结作业
    sdn2017 第三次作业
    Golang 探索对Goroutine的控制方法
    SDN2017 第二次实验作业
    SDN2017 第二次作业
    Redis在游戏服务器中的应用
    手机游戏开发
    手机游戏开发
  • 原文地址:https://www.cnblogs.com/Leohh/p/7704438.html
Copyright © 2011-2022 走看看