hdoj 1394 Minimum Inversion Number 【线段数】

题目大意:求移动数列中的第一个元素到最后一位时的最少逆序数。(进行n次移动,求移动过程中最少的逆序数)

难点:

一:什么是逆序数? 定义: 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。逆序数为偶数的排列称为偶排列;逆序数为奇数的排列称为奇排列。如2431中,21,43,41,31是逆序,逆序数是4,为偶排列。

二:怎么求?

此题分析一下有个技巧对于这道题因为是0~n-1所以我们可以通过下标就可以判别大小,假设此时数列第一个元素为a, 那么当a移动到最后一位的时候,比他小的数(有a个)的逆序数都要减一,比他大的(有n-1-a)都要加一,此时总的逆序数增加了n-1-a-a个;

我想到有两种思路:1》普通的搜索, 但测试数据5000,太大,而且每次查找逆序数的个数后,都要往后移一位,TL,可能性很大。放弃了这一种思路。

2》线段树,只需要找出来初始数组的逆序数,就可以递推其他的数列的逆序数了(根据上面的技巧);

AC by SWS

题目链接http://acm.hdu.edu.cn/showproblem.php?pid=1394

代码:

#include<stdio.h>
#include<string.h>
#define MAXN 5005
#define LC l, m, rt<<1
#define RC m+1, r, rt<<1|1
int sum[MAXN<<2];
int s[MAXN];
void creat(int l, int r, int rt)  //创建线段树,但因为初始全为0, 可以不用这样,直接一个memset就可以了
{
	if(l ==r){
		sum[rt] = 0;
		return;
	}
	int m = (l+r)>>1;
	creat(LC);
	creat(RC);
	sum[rt] = sum[rt<<1]+sum[rt<<1|1];
}
void update(int p, int l, int r, int rt)
{
	if(l == r){
		sum[rt]++; //标记等于此位置的序号的数已更新
		return;
	}
	int m = (l+r)>>1;
	if(p<=m) update(p, LC);
	else update(p, RC);
	sum[rt] = sum[rt<<1]+sum[rt<<1|1];
}
int query(int le, int ri, int l, int r, int rt)
{
	if(le <= l&&r<= ri)
	return sum[rt];
	int res = 0;
	int m = (l+r)>>1;
	if(le <= m) res+=query(le, ri, LC);
	if(ri > m) res+= query(le, ri, RC);
	return res;
}
int main()
{
	int n;
	while(scanf("%d", &n) == 1){
		//memset(sum, 0, sizeof(sum));
		creat(0, n-1, 1);
		int sum = 0; //统计初始数列的逆序数
		for(int i = 0; i < n; i ++){
			scanf("%d", &s[i]);
			sum += query(s[i], n-1, 0, n-1, 1);  //关于这个为什么是s[i], n-1, 是因为要判断比s[i]大的数是不是已经更新到了线段树之中,返回此时的相对于s[i]的逆序数)
			update(s[i], 0, n-1, 1);
		}
		int ans  = sum;
		for(int i = 0; i < n; i ++){ //每移动一位总数增加<span style="color: rgb(51, 51, 51); font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; text-indent: 28px; ">n-1-a-a</span>
			sum += n-s[i]-1-s[i];
			ans = ans< sum?ans:sum; 判断是否为最小
		}
		printf("%d\n", ans);
	}
	return 0;
}

hdoj 1394 Minimum Inversion Number 【线段数】

时间: 2024-10-10 18:07:21

hdoj 1394 Minimum Inversion Number 【线段数】的相关文章

hdoj 1394 Minimum Inversion Number【线段树求逆序对】

求逆序对有很多算法,这里说一下线段树求逆序对的思想. 知识点:线段树,逆序对,单点更新,成段求和 算法:线段树求逆序数的前提条件是要离散化,变成连续的点,首先建树,每个节点设置一个num值为0. 然后根据逆序对的定义,前面出现过的比当前数大的个数的和,我们需要求前面的比他大的数,其实就相当于从当前a[i]点对他后面所有出现过的数求和一次.然后把当前点的值在线段树叶子节点变为1,表示出现过,并向上更新到线段树里面.比如说样例4 2 1 5 3 首先4后面没有值,4更新为1,4--5区间更新为1,1

hdu 1394 Minimum Inversion Number 线段树 点更新

// hdu 1394 Minimum Inversion Number 线段树 点更新 // // 典型线段树的单点更新 // // 对于求逆序数,刚开始还真的是很年轻啊,裸的按照冒泡排序 // 求出最初始的逆序数,然后按照公式递推,结果就呵呵了 // // 发现大牛都是用线段树和树状数组之类的做的,而自己又在学 // 线段树,所以就敲了线段树. // // 线段树的节点保存一段区间( L,R )内0,1...n一共出现了多少个. // 因为每个数是0,1,2...n-1且没有重复的数字. /

HDU 1394 Minimum Inversion Number.(线段树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 ~~~~ 早起一发线段树,开心又快乐.这题暴力也能水过,同时线段树的效率也就体现的尤为明显了,看了大牛的博客,说是还可以用树状数组,点树和合并序列写,现在还不懂,留着以后在写吧. ~~~~ 大致题意:给定一个数字序列,同时由此可以得到n个序列, 要求从n个序列中找到逆序数最小的序列,输出最小逆序数. 首先介绍下逆序数的概念: 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面

逆序数2 HDOJ 1394 Minimum Inversion Number

题目传送门 1 /* 2 求逆序数的四种方法 3 */ 1 /* 2 1. O(n^2) 暴力+递推 法:如果求出第一种情况的逆序列,其他的可以通过递推来搞出来,一开始是t[1],t[2],t[3]....t[N] 3 它的逆序列个数是N个,如果把t[1]放到t[N]后面,逆序列个数会减少t[1]个,相应会增加N-(t[1]+1)个 4 */ 5 #include <cstdio> 6 #include <cstring> 7 #include <algorithm>

HDOJ 1394 Minimum Inversion Number 求循环串的最小逆序数(暴力&amp;&amp;线段树)

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

HDU 1394 Minimum Inversion Number (线段树,单点更新)

C - Minimum Inversion Number Crawling in process... Crawling failed Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 1394 Appoint description: System Crawler (2015-08-17) Description The inversio

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

HDU 1394 Minimum Inversion Number (线段树,暴力)

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 seq

hdu 1394 Minimum Inversion Number 线段树

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