您的位置:首页 > 其它

杭电hdu 1394 Minimum Inversion Number 线段树练习

2012-04-07 20:19 330 查看
http://acm.hdu.edu.cn/showproblem.php?pid=1394

刚看的时候感觉和线段树并没有关系啊,但是看别人的解题报告却都用了很多的方法,还有用的就是线段树,树状数组,暴力也过了,还有归并排序也能通过,感觉就是条条道路通罗马啊,但是我却想不出来一个可以用的方法。也可能是我把以前学的数学知识给忘的差不多了的原因吧,回去还要好好补数学呢。

想解决这个题首先得知道什么是逆序数,这是数学中概念,经过查找,我回想起来了逆序数就是一列数中出现逆序的个数。左移序列之后得到新的序列的逆序数的个数就等与当前总的个数减左边的数的逆序数a[i],然后加上新增的逆序数n-a[i]-1;这样这个题的思路就有了。

暴力求解就是求每个数的逆序数,然后加到一起。之后再左移序列。

//暴力解法
#include <stdio.h>
#include <string.h>

int main()
{
int tmp[5001], b[5001];
int n, i, j;
while(scanf("%d", &n)!=EOF){
for(i = 0; i < n; i ++){
scanf("%d", &tmp[i]);
}
__int64 t = 0;
memset(b, 0, sizeof(b));
for(i = 0; i < n; i ++){
for(j = i+1; j < n; j ++){
if(tmp[i] > tmp[j])
b[i] ++;
}
t += b[i];
}
__int64 min = t;
for(i = 0; i < n; i ++){
//			printf("t = %I64d\n", t);
t = t-tmp[i]+n-1-tmp[i];
if(min > t)min = t;
}
//		printf("t = %d\n", t);
printf("%I64d\n", min);
}
return 0;
}
使用线段树解此题时,每次都要查找在该数出现之前已经出现的大于该数的个数,该个数就是该数的逆序数,然后累加求出全部的逆序数,最后进行求解。

//线段树解法
#include <stdio.h>

#define MAX 5005

typedef struct _node
{
int left;
int right;
int value;
}node;

node no[MAX];

int ans;

void initTree(int left, int right, int i)
{
no[i].left = left, no[i].right = right;
no[i].value = 0;
if(left == right)return;
int mid = (left+right)/2;
initTree(left, mid, i*2);
initTree(mid+1, right, i*2+1);
}
//update
void modify(int index, int i)
{
if(no[i].left == no[i].right){
no[i].value = 1;
return;
}
int mid = (no[i].left + no[i].right)>>1;
if(index <= mid){
modify(index, i*2);
}
else {
modify(index, i*2+1);
}
no[i].value = no[i*2].value + no[i*2+1].value;
}
//query
void query(int left, int right, int i)
{
if(no[i].left == left && no[i].right == right){
ans += no[i].value;
return ;
}
int mid = (no[i].left + no[i].right)/2;
if(right <= mid){
query(left, right, i*2);
}
else if(left > mid){
query(left, right, i*2+1);
}
else {
query(left, mid, i*2);
query(mid + 1, right, i*2+1);
}
}

int main()
{
int n, i, a[MAX];
while(scanf("%d", &n)!=EOF){
initTree(0, n-1, 1);
ans = 0;
for(i = 0; i < n; i ++){
scanf("%d", a+i);
query(a[i], n-1, 1);
modify(a[i], 1);
}
int min = ans;
for(i = 0; i < n; i ++){
ans = ans - a[i] + n - a[i] - 1;
if(min > ans)min = ans;
}
printf("%d\n", min);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: