http://acm.hdu.edu.cn/showproblem.php?pid=1394

题意:

给定一个n,然后又n个数字,首先,这些数字的大小是从0开始到n-1,比如样例n=10,则这十个数就是0,1,2,3,4,5,6,7,8,9,然后再将他们的顺序打乱来,构成一个数组.

对于数组a,每次把最前面的下标的数放到末尾去,然后求n次操作中最小的逆序数的个数是多少.

其中逆序数是当i<j时ai>aj.

题解:

首先由于数字给的很小,只有5000个,所以可以暴力.

由于题目给的数字是从0到n-1.这个很重要,否则就要额外的加处理.

先讲讲暴力的写法:

首先对于一个数组a,我们有一个初始的逆序对的个数,这个可以直接两个for循环求出.

然后重点来了,由于每次我们需要将数组的第一个数移动到末尾去,这个时候逆序对的个数就改变了.

比如对于第一个数c,他后面会有t个逆序对数,由于数大小是固定的,也就是说他的逆序数就是数组中比他小的数的个数,所以这里逆序数个数 t1=c,这样一来剩下的数都是他的顺序数了,也就是说顺序数个数 t2=n-c-1.

比如样例

10

1 3 6 9 0 8 5 7 4 2

这里逆序数有22个

对于数字1来说,其逆序数只有1个,就是0,而顺序数就是后面的8个其他数字.

然后再讲讲变化,试想一下,当我们把第一个数字放到最末尾去,那么对于整个数组的数来说,逆序对的个数就会减少 t1个,而同时又会增加 t2个.

还是拿样例来说,当我们把1移动到了最后面去,这时

10

3 6 9 0 8 5 7 4 2 1

这个时候逆序数就是 22-1+8=29个逆序数了.我们可以看到,由于移到了最后一个,当他在第一个位置时与他是逆序数的数都会变得反过来,同时与他是顺序对的数也会反过来变成逆序对.

所以对于所有的数组,我们只要用一个for来循环一遍就可以求得每次的逆序数的总数,取其中最小的数就可以了.

暴力AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int dir[][]={{,},{,},{,},{,-},{-,},{-,-},{,-},{-,}};
#define pi acos(-1)
#define ls rt<<1
#define rs rt<<1|1
#define me0(s) memset(s,0,sizeof(s))
#define me1(s) memset(s,1,sizeof(s))
#define mef(s) memset(s,-1,sizeof(s))
#define meinf(s) memset(s,inf,sizeof(s))
#define llinf 1e18
#define inf 1e9
const int N=;
int a[N];
int main(int argc, char * argv[]){
int n;
while(~scanf("%d",&n)){
int sum=;
for(int i=;i<n;i++){
scanf("%d",&a[i]);
}
for(int i=;i<n;i++){
for(int j=i+;j<n;j++){
if(a[j]<a[i]){
sum++;
}
}
}//求出最开始序列的逆序对的数目
cout<<sum<<endl;
int ans=sum;
for(int i=;i<n;i++){
sum=sum-(a[i]-n+)-a[i];
if(ans>sum) ans=sum;
}
printf("%d\n",ans);
}
return ;
}

以上是暴力的写法.

然后有线段树的写法,线段树的写法完全就是取代第一步,求出初始的序列的逆序数的个数,因为暴力的话复杂度是n2的复杂度,数据稍微大点就会TLE了,所以要么用归并排序要么用线段树就可以很好的对其进行优化成nlogn的复杂度.

叶子节点代表的左右端点a[i],节点中sum维护是否插入了a[i],按顺序插入a[i],每次插入查询区间[a[i],n-1]中的点数,因为这个区间内的点都比tree[i]先插入且比tree[i]大,所以这个区间内的点的个数就等于a[i]的逆序数。

线段树AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int dir[][]={{,},{,},{,},{,-},{-,},{-,-},{,-},{-,}};
#define pi acos(-1)
#define ls rt<<1
#define rs rt<<1|1
#define me0(s) memset(s,0,sizeof(s))
#define me1(s) memset(s,1,sizeof(s))
#define mef(s) memset(s,-1,sizeof(s))
#define meinf(s) memset(s,inf,sizeof(s))
#define llinf 1e18
#define inf 1e9
const int N=1e4+;
int sum[N<<];
void pushup(int rt){
sum[rt]=sum[ls]+sum[rs];
}
void build(int l,int r,int rt){
sum[rt]=;
if(l==r) return ;
int m=(l+r)/;
build(l,m,ls);
build(m+,r,rs);
pushup(rt);
}
void update(int l,int r,int p,int rt){
if(l==r){
sum[rt]++;
return ;
}
int m=(l+r)/;
if(p<=m) update(l,m,p,ls);
if(p>m) update(m+,r,p,rs);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt){
if(L<=l&&R>=r) return sum[rt];
int ans=;
int m=(l+r)/;
if(L<=m) ans+=query(L,R,l,m,ls);
if(R>m) ans+=query(L,R,m+,r,rs);
return ans;
}
int a[N];
int main(int argc, char * argv[]){
int n;
while(~scanf("%d",&n)){
build(,n-,);
int sum=;
for(int i=;i<n;i++){
scanf("%d",&a[i]);
sum+=query(a[i],n-,,n-,);
update(,n-,a[i],);
}
int ret=sum;
for(int i=;i<n;i++){
sum+=n-*a[i]-;
ret=min(ret,sum);
}
printf("%d\n",ret);
}
return ;
}

hdu-1394(线段树求最小逆序数)的更多相关文章

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

    HDU 1394 Minimum Inversion Number(线段树求最小逆序数对) ACM 题目地址:HDU 1394 Minimum Inversion Number 题意:  给一个序列由 ...

  2. HDU 1394 Minimum Inversion Number(最小逆序数 线段树)

    Minimum Inversion Number [题目链接]Minimum Inversion Number [题目类型]最小逆序数 线段树 &题意: 求一个数列经过n次变换得到的数列其中的 ...

  3. hdu 1394 (线段树求逆序数)

    <题目链接> 题意描述: 给你一个有0--n-1数字组成的序列,然后进行这样的操作,每次将最前面一个元素放到最后面去会得到一个序列,那么这样就形成了n个序列,那么每个序列都有一个逆序数,找 ...

  4. HDU 1394 线段树求逆序对

    Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java ...

  5. HDU 1394.Minimum Inversion Number-最小逆序数-完全版线段树(单点增减、区间求和)

    HDU1394.Minimum Inversion Number 这个题求最小逆序数,先建一个空的树,然后每输入一个值,就先查询一下,查询之后,更新线段树,然后遍历一遍,每次将第一个数放到最后之后,减 ...

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

    Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java ...

  7. hdu 1394(线段树) 最小逆序数

    http://acm.hdu.edu.cn/showproblem.php?pid=1394 给出一列数组,数组里的数都是从0到n-1的,在依次把第一个数放到最后一位的过程中求最小的逆序数 线段树的应 ...

  8. hdu 1394 线段树计算逆序数

    线段树计算逆序数的原理: 用线段树来统计已插入的数的个数(所以要保证最大的那个数不能太大,否则数组都开不了),然后每插入一个数,就查询比插入的数大的个数,累加即可. 这个题还有一个特点就是,题目给的是 ...

  9. HDU 1394 线段树or 树状数组~

    Minimum Inversion Number Description The inversion number of a given number sequence a1, a2, ..., an ...

随机推荐

  1. msql数据库基础

    一.数据库操作 1.显示数据库 SHOW DATABASES; SHOW CREATE DATABASE 数据库名称; #数据库的创建信息 2.创建数据库 #utf8 CREATE DATABASE ...

  2. Jmeter-【beanshell处理器】-随机获取手机号

    一.通过操作变量 二.引用外部Java文件 三.引用外部class文件

  3. 01退背包——bzoj2287

    退背包就是限制某一件物品不可取的方案数 先做出无限制的方案数,然后对于当前不可取的物品,dp2[j]表示不取改物品情况下,取得体积为j的方案数 有状态方程 dp2[j]=dp1[j]-dp2[j-w[ ...

  4. hdu多校第九场 1006 (hdu6685) Rikka with Coin 暴力

    题意: 有一些1毛,2毛,5毛,1块的钢镚,还有一些价格不同的商品,现在要求你带一些钢镚,以保证这些商品中任选一件都能正好用这些钢镚付账,问最少带多少钢镚. 题解: 对于最优解,1毛的钢镚最多带1个, ...

  5. java: java中的 getInstance() 的理解

    原文地址:https://blog.csdn.net/qq_26293573/article/details/78184844 在单例模式下使用 . 单例模式:所谓单例模式就是一个类有且只有一个实例, ...

  6. 唯一id

    package com.debug.kill.server.utils; /** * Created by Administrator on 2019/6/20. */ import org.apac ...

  7. 随笔-ansible-3

    关于循环的一些事: 是否是因为模块的原因? item适用于copy,但不适用于yum.虽然出现了警告,但并不表示不能用.功能还是不受影响的. 在上例中,我们使用了yum.copy.service模块( ...

  8. mysql sql时间戳格式化语句

    FROM_UNIXTIME(c.lastUpdateTime/1000,'%Y-%c-%d %h:%i:%s' ) as updatetime; select c.roleid, r.username ...

  9. 关于Excel的ctrl+方向键失效的解决方法

    在Excel中按方向键,出现了类似滚动条的效果,即按下,表格就往下滚了一格.正常的情况应该是选中的单元格往下移动一格.其实这是一个很正常的情况,只要按一下Scroll Lock键就可以了,对于没有Sc ...

  10. WIN10安装CUDA10 cuDNN

    文章目录 CPU和GPU 什么是CUDA 什么是cuDNN WIN10安装CUDA10 WIN10安装cuDNN CPU和GPU CPU和GPU是不一样的计算机设备,CPU作为计算机心脏一直被人们所认 ...