HDU 1394 (逆序数) Minimum Inversion Number

原来求逆序数还可以用线段树,涨姿势了。

首先求出原始序列的逆序数,然后递推每一个序列的逆序数。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5
 6 const int maxn = 20000 + 10;
 7
 8 int n, p, qL, qR;
 9 int sum[maxn], a[5000 + 10];
10
11 void update(int o, int L, int R)
12 {
13     if(L == R) { sum[o]++; return; }
14     int M = (L + R) / 2;
15     if(p <= M) update(o*2, L, M);
16     else update(o*2+1, M+1, R);
17     sum[o] = sum[o*2] + sum[o*2+1];
18 }
19
20 int query(int o, int L, int R)
21 {
22     if(qL <= L && qR >= R) return sum[o];
23     int ans = 0;
24     int M = (L + R) / 2;
25     if(qL <= M) ans += query(o*2, L, M);
26     if(qR > M) ans += query(o*2+1, M+1, R);
27     return ans;
28 }
29
30 int main()
31 {
32     //freopen("in.txt", "r", stdin);
33
34     while(scanf("%d", &n) == 1)
35     {
36         memset(sum, 0, sizeof(sum));
37
38         for(int i = 0; i < n; i++) scanf("%d", &a[i]);
39         int inv = 0;
40         for(int i = 0; i < n; i++)
41         {
42             p = a[i];
43             qL = a[i]; qR = n - 1;
44             inv += query(1, 0, n - 1);
45             update(1, 0, n - 1);
46         }
47         int ans = inv;
48         for(int i = 0; i < n; i++)
49         {
50             inv = inv + n - a[i]*2 - 1;
51             ans = min(ans, inv);
52         }
53         printf("%d\n", ans);
54     }
55
56     return 0;
57 }

线段树

既然要求逆序数了,干脆树状数组,归并排序也都试一试。

由于树状数组lowbit的特点,所以数组下标是从1开始的。但是树状数组要比线段树好写很多。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5
 6 const int maxn = 5000 + 10;
 7 int n;
 8 int a[maxn], s[maxn];
 9
10 inline int lowbit(int x) { return x&(-x); }
11
12 int sum(int x)
13 {
14     int ans = 0;
15     while(x > 0) { ans += s[x]; x -= lowbit(x); }
16     return ans;
17 }
18
19 void add(int x, int d)
20 {
21     while(x <= n) { s[x] += d; x += lowbit(x); }
22 }
23
24 int main()
25 {
26     //freopen("in.txt", "r", stdin);
27
28     while(scanf("%d", &n) == 1)
29     {
30         memset(s, 0, sizeof(s));
31         for(int i = 0; i < n; i++) { scanf("%d", &a[i]); a[i]++; }
32         int inv = 0;
33         for(int i = 0; i < n; i++)
34         {
35             inv += sum(n) - sum(a[i]);
36             add(a[i], 1);
37         }
38         int ans = inv;
39         for(int i = 0; i < n; i++)
40         {
41             inv = inv + n + 1 - a[i]*2;
42             ans = min(ans, inv);
43         }
44         printf("%d\n", ans);
45     }
46
47     return 0;
48 }

树状数组

下面是归并排序,_(:зゝ∠)_

代码不长,但是感觉还是挺容易写错的。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5
 6 const int maxn = 5000 + 10;
 7 int n, inv;
 8 int a[maxn], b[maxn], T[maxn];
 9
10 void MergeSort(int x, int y)
11 {
12     if(y - x > 1)
13     {
14         int m = (x + y) / 2;
15         int p = x, q = m, i = x;
16         MergeSort(x, m); MergeSort(m, y);
17         while(p < m || q < y)
18         {
19             if(q >= y || (p < m && a[p] <= a[q])) T[i++] = a[p++];
20             else { T[i++] = a[q++]; inv += m - p; }
21         }
22         for(i = x; i < y; i++) a[i] = T[i];
23     }
24 }
25
26 int main()
27 {
28     //freopen("in.txt", "r", stdin);
29
30     while(scanf("%d", &n) == 1)
31     {
32         for(int i = 0; i < n; i++) { scanf("%d", &a[i]); b[i] = a[i]; }
33         inv = 0;
34         MergeSort(0, n);
35         int ans = inv;
36         for(int i = 0; i < n; i++)
37         {
38             inv = inv + n - 1 - b[i]*2;
39             ans = min(ans, inv);
40         }
41         printf("%d\n", ans);
42     }
43
44     return 0;
45 }

归并排序

时间: 2024-08-10 01:52:54

HDU 1394 (逆序数) Minimum Inversion Number的相关文章

【线段树】HDU 1394 Minimum Inversion Number

minimum inversion number:最小逆序数 Minimum Inversion NumberTime Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 9367    Accepted Submission(s): 5754 Problem Description The inversion number of a given nu

hdu 1394 Minimum Inversion Number 逆序数/树状数组

Minimum Inversion Number Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=1394 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

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): 13942    Accepted Submission(s): 8514 Problem Description The inversion number of a given number sequence a1, a2, ..., a

hdu 1394 Minimum Inversion Number (裸树状数组 求逆序数)

题目链接 题意: 给一个n个数的序列a1, a2, ..., an ,这些数的范围是0-n-1, 可以把前面m个数移动到后面去,形成新序列: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)求这些序列中,逆序数最少的

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

题目地址:HDU 1394 这题可以用线段树来求逆序数. 这题的维护信息为每个数是否已经出现.每次输入后,都从该点的值到n-1进行查询,每次发现出现了一个数,由于是从该数的后面开始找的,这个数肯定是比该数大的.那就是一对逆序数,然后逆序数+1.最后求完所有的逆序数之后,剩下的就可以递推出来了.因为假如目前的第一个数是x,那当把他放到最后面的时候,少的逆序数是本来后面比他小的数的个数.多的逆序数就是放到后面后前面比他大的数的个数.因为所有数都是从0到n-1.所以比他小的数就是x,比他大的数就是n-

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

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

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

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 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,

HDU 1394——Minimum Inversion Number(最小逆序数)

题意: 给定一个序列,里面的数是0到n-1,  每次要把第一个数放到最后一个数,重复n次,求n次操作中最小的逆序数是多少? 思路: 先求出初始的逆序数,然后每移动第一个数到最后面,那么逆序数要减去比它小的数的个数,加上比它大的数的个数. 如果我输入的数是a[i],那么比它小的数的个数就有a[i]个,比它大的数的个数就有n-1-a[i]个 方法:    归并排序 ,树状数组,线段树 归并排序代码: #include<iostream> #include<cstring> #inclu

HDU 1394 Minimum Inversion Number(逆序数)

题目链接:HDU 1394 Minimum Inversion Number [题意]给你一个1~N的数字组成的初始序列,然后每一次都将第一个数字移到最后,形成新的序列,然后求出这些序列的逆序数中的最小值. [思路]开始可以用任意一种方法(线段树 or 暴力 or 树状数组)计算出初始数列的逆序数sum,这里我比较懒,就直接用的暴力找的sum,对于a[i](0~~n-1),每挪一个,用sum减去挪之前它右边比它小的数的个数(也就是a[i]个),再用sum加上挪之后左边比它大的数的个数(也就是n-