hdu1394Minimum Inversion Number(线段树,求最小逆序数)

Minimum Inversion Number

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 25092    Accepted Submission(s): 14816

Problem Description

The inversion number of a given number sequence a1, a2, ..., an is the number of pairs (ai, aj) that satisfy i < j and ai > aj.

For a given sequence of numbers a1, a2, ..., an, if we move the first m >= 0 numbers to the end of the seqence, we will obtain another sequence. There are totally n such sequences as the following:

a1, a2, ..., an-1, an (where m = 0 - the initial seqence)
a2, a3, ..., an, a1 (where m = 1)
a3, a4, ..., an, a1, a2 (where m = 2)
...
an, a1, a2, ..., an-1 (where m = n-1)

You are asked to write a program to find the minimum inversion number out of the above sequences.

Input

The input consists of a number of test cases. Each case consists of two lines: the first line contains a positive integer n (n <= 5000); the next line contains a permutation of the n integers from 0 to n-1.

Output

For each case, output the minimum inversion number on a single line.

Sample Input

10

1 3 6 9 0 8 5 7 4 2

Sample Output

16

第一题线段树题。

学习https://www.cnblogs.com/ziyi--caolu/archive/2013/01/15/2860768.html

题意:给出一列数,每次把最前面一个移动最后面,都是一个新的序列,要求计算最小的逆序数并输出。

题解:在输入的时候计算线段树中有多少是比当前的数大的,表示当前序列中由该数组成逆序数,用a[i]来保存,全部输入完之后就获得总的逆序数。然后开始把前面的的数一个个移到最后面,每次计算这个序列的逆序数(用a[i]来实现,代码里注释了),并更新一下最小逆序数。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 5005
 4 struct node
 5 {
 6     int l,r;
 7     int num;
 8 }tree[4*N];
 9 void creat(int i,int l,int r) {
10     int mid=(l+r)/2;
11     tree[i].l=l;
12     tree[i].r=r;
13     tree[i].num=0;
14     if(l==r) {
15         return ;
16     }
17     creat(i*2,l,mid);
18     creat(i*2+1,mid+1,r);
19 }
20 void update(int i,int k) {
21     if(tree[i].l==k&&tree[i].r==k) {
22         tree[i].num=1;
23         return ;
24     }
25     int mid=(tree[i].l+tree[i].r)/2;
26     if(k<=mid)
27         update(i*2,k);
28     else
29         update(i*2+1,k);
30     tree[i].num=tree[i*2].num+tree[i*2+1].num;
31 }
32 int getsum(int i,int k,int n) {//统计线段树中大于k的有多少个
33     if(k<=tree[i].l&&tree[i].r<=n) {
34         return tree[i].num;
35     } else {
36         int mid=(tree[i].l+tree[i].r)/2;
37         int sum1=0,sum2=0;
38         if(k<=mid)
39             sum1=getsum(i*2,k,n);
40         if(n>mid)
41             sum2=getsum(i*2+1,k,n);
42         return sum1+sum2;
43     }
44 }
45 int a[N];
46 int main() {
47     int n;
48     while(~scanf("%d",&n))
49     {
50         memset(a,0,sizeof(a));
51         creat(1,0,n-1);int ans=0;
52         for(int i=0;i<n;i++)
53         {
54             scanf("%d",&a[i]);
55             ans+=getsum(1,a[i]+1,n-1);//每次统计大于该数的有多少个
56             update(1,a[i]);//插入,更新结点
57         }
58         int minn=ans;//把全部输入完后,还没有移动过的逆序数赋给minn
59         for(int i=0;i<n;i++)
60         {
61             ans=ans+n-1-a[i]-a[i];//这里的a[i]表示可以和a[i]组合逆序的对数,每次把最前面的数移动最后面,就相当于
62             minn=min(minn,ans);//有a[i]对逆序不能成立了,但相应的增加了n-1-a[i]对逆序
63         }
64         printf("%d\n",minn);
65     }
66     return 0;
67 }

原文地址:https://www.cnblogs.com/fqfzs/p/9892396.html

时间: 2024-11-06 13:57:49

hdu1394Minimum Inversion Number(线段树,求最小逆序数)的相关文章

HDU 1394 Minimum Inversion Number(线段树求最小逆序数对)

HDU 1394 Minimum Inversion Number(线段树求最小逆序数对) ACM 题目地址:HDU 1394 Minimum Inversion Number 题意: 给一个序列由[1,N]构成,可以通过旋转把第一个移动到最后一个. 问旋转后最小的逆序数对. 分析: 注意,序列是由[1,N]构成的,我们模拟下旋转,总的逆序数对会有规律的变化. 求出初始的逆序数对再循环一遍就行了. 至于求逆序数对,我以前用归并排序解过这道题:点这里. 不过由于数据范围是5000,所以完全可以用线

Minimum Inversion Number(线段树单点更新+逆序数)

Minimum Inversion Number(线段树单点更新+逆序数) Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Description The inversion number of a given number sequence a1, a2, ..., an is the number of pairs (ai, aj) that satisfy

HDU1394 线段树求最小逆序数

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1394 求最小的逆序数,在此贴下逆序数的概念: 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中逆序的总数就称为这个排列的逆序数.逆序数为偶数的排列称为偶排列:逆序数为奇数的排列称为奇排列.如2431中,21,43,41,31是逆序,逆序数是4,为偶排列. 也是就说,对于n个不同的元素,先规定各元素之间有一个标准次序(例如n个 不同的自然数,可规

HDU1394-Minimum Inversion Number-归并排序求最小逆序数

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 理解了归并排序,学习了一下别人的博客,有把这个题目给敲了一遍... 这道题我用归并排序是我目前过的最快的算法62ms...当然,在我得博客里也有有线段树和树状数组求逆序数的模板: 这里我就没有离散化,还不能算是所有逆序数的模板... 对于归并排序不太了解的我推荐一个博客,里面有很详细的图解:链接:http://www.cnblogs.com/jillzhang/archive/2007/09/

Hdu1394Minimum Inversion Number线段树

这个网上一搜一大堆,就是先求一个,其余的for一遍搞出来. #include<stdio.h> #include<stdlib.h> #define max 5555 int sum[max * 4]; int min(int a, int b) { if (a>b) return b; else return a; } void fuqin(int a) { sum[a] = sum[a * 2] + sum[a * 2 + 1]; } void build(int l,

HDU 1394- Minimum Inversion Number(线段树求逆序数)

Minimum Inversion Number Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 1394 Appoint description:  System Crawler  (2015-04-13) Description The inversion number of a given number sequence a1, a

HDU1394 Minimum Inversion Number 【线段树】+【逆序数】

Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 9864    Accepted Submission(s): 6069 Problem Description The inversion number of a given number sequence a1, a2, ..., an

HDU1394_Minimum Inversion Number(线段树/逆序数)

解题报告 题目传送门 题意: 给n个数,每次左移一位,求最小逆序数. 思路: 如果每次左移一位求一次逆序数肯定不行的. 可以知道,每次左移一位,也就是第一个数移到最后一位,逆序数应该减去第一个数以后比第一个数小的个数,再加上比第一个数大的个数. 原本用线段树求出每一位后面比这一位小的个数再用上面的办法求最小逆序数,没有想到每一次移动会导致后面比它本身大的数都要加1. 这题巧妙就在这n个数都在0-n里面,且没有重复. 所以第一个数以后比第一个数小的个数就是第一个数的数值.比它大就是n-1-第一个数

Hdu 1394 Minimum Inversion Number(线段树或树状数组)

Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 11981    Accepted Submission(s): 7321 Problem Description The inversion number of a given number sequence a1, a2, ..., a