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

BZOJ_2058_[Usaco2010 Nov]Cow Photographs_逆序对

时间:2018-02-10 16:56:40      阅读:167      评论:0      收藏:0      [点我收藏+]

标签:body   usaco   string   题意   二分   位置   main   需要   拍照   

BZOJ_2058_[Usaco2010 Nov]Cow Photographs_逆序对

题意:

奶牛的图片 Farmer John希望给他的N(1<=N<=100,000)只奶牛拍照片,这样他就可以向他的朋友炫耀他的奶牛.这N只奶牛被标号为1..N. 在照相的那一天,奶牛们排成了一排.其中第i个位置上是标号为c_i(1<=c_i<=N)的奶牛.对于奶牛的站位,Farmer John有他自己的想法. FJ是这么想的,标号为i(1<=i<=n-1)的奶牛只能站在标号为i+1的奶牛的左边,而标号为N的奶牛只能站在标号为1的奶牛的左边.当然,没有牛可以站在队列中最左边的奶牛的左边了.也就是说,最左边的奶牛编号是随意的. 这些奶牛都非常的饿,急切的希望吃到FJ承诺的在拍照后的大餐,所以FJ想尽快的拍照.奶牛们的方向感非常的不好,所以FJ每一分钟只可以选择相邻的两只奶牛然后让他们交换位置.FJ最小需要多少时间就能使奶牛站成一个可以接受的序列? 比方说一个有5只奶牛的例子,一开始序列是这样的: 左边 右边 3 5 4 2 1 第一分钟,FJ可以交换第二队奶牛(即5和4),交换后的队列: 3 4 5 2 1 第二分钟,FJ交换最右边的一对,序列变成这样: 3 4 5 1 2 这样,只用了2分钟,就是序列变为了一个FJ所希望的序列.

分析:

我们分析一下样例。首先将序列变成12345需要的步数为序列的逆序对个数,那么考虑如何将序列变成23451,我们把原序列的1变成6,发现只需要求新序列的逆序对,新序列的逆序对其实就是减去1对序列的贡献再加上6对序列的贡献,只需要维护一下每个数在原序列中出现的位置就可以转移,34512同理。那么我们可以递推求出每个最后一个数为i的序列的逆序对,取min既是答案。

代码:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 using namespace std;
 5 #define N 100050
 6 int n,a[N],c[N],b[N];
 7 #define LL long long
 8 void fix(int x)
 9 {
10     while(x<=n)
11     {
12         c[x]++;
13         x+=x&(-x);
14     }
15 }
16 int inq(int x)
17 {
18     int re=0;
19     while(x)
20     {
21         re+=c[x];
22         x-=x&(-x);
23     }
24     return re;
25 }
26 int main()
27 {
28     LL ans=0;
29     scanf("%d",&n);
30     for(int i=1;i<=n;i++)
31     {
32         scanf("%d",&a[i]);
33         b[a[i]]=i;
34         ans+=(i-1-inq(a[i]));
35         fix(a[i]);
36     }
37     LL now=ans;
38     for(int i=1;i<n;i++)
39     {
40         now=now-b[i]+1+n-b[i];
41         ans=min(ans,now);
42     }
43     printf("%lld",ans);
44 }

 

BZOJ_2058_[Usaco2010 Nov]Cow Photographs_逆序对

标签:body   usaco   string   题意   二分   位置   main   需要   拍照   

原文地址:https://www.cnblogs.com/suika/p/8438942.html

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