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): 17737 Accepted Submission(s): 10763
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.
1 3 6 9 0 8 5 7 4 2
题目链接:HDU 1394
主要操作:单点更新,区间求和
通过此题学习到了如何用NlogN的时间来求一个数列的逆序对个数(简称逆序数),先上暴力求法
暴力求法代码:
int cnt=0;
for (int i=1; i<=n; ++i)
{
for (int j=i+1; j<=n; ++i)
{
if(arr[i]>arr[j])//i<j但arr[i]却大于arr[j],这就是一个逆序对<arr[i],arr[j]>
++cnt;
}
}
printf("%d\n",cnt);//cnt即为逆序对个数
那显然题目中的n可达5000,一平方估计得TLE,然后学习了一下用树状数组或线段树来求的方法。
主要思路:按照顺序读入一个数,记为arr[i]吧,然后对【arr[i]+1, end】求和记为sum,为什么这样就可以得到arr[i]的逆序对呢?
想想逆序对的定义:i<j且arr[i]>arr[j](假设i<j前面),显然题目按顺序读入已经无形中满足了i<j的要求,也就是说正常上升序列应该是i<j且arr[i]<arr[j] ,但是你出现了一个arr[i]>arr[j],也就是说让【arr[j],end】之间的arr[i]这个点的值发生变化(变为1),那我一旦对【arr[j]+1,end】求和就肯定会出现sum>0的情况,那这个大于0是谁造成的呢?就是某个大于arr[j]的arr[i],不用管他是谁,反正只要arr[i]>arr[j]就能对【arr[j],end】一段求和造成影响,那显然一个arr[i]与arr[j]能组成一对,那n个就组成n对,那每一个的影响值都设为1,那求和求出来的就是对数。
然后得到了最初的逆序数怎么往后推?那就考虑开头的数移到末尾的影响,显然比开头的arr[0]小的数有arr[0]-1个记为low(题目中范围为0~n-1的自然数,且会全部出现且不重复),然后除去开头的数一共有n-1个,那么剩下比arr[0]大的数有(n-1)-(arr[0]-1)个即n-arr[0]个记为up。然后看开头的移到末尾,原本的逆序数变成了正序,原本的正序变成了逆序,因此移动之后的sum'=sum+(正序变为逆序就要加)up-(逆序变为正序就要减)low。
代入n与arr[0]得到sum'=sum+n-arr[0]-(arr[0]-1)=sum+n-arr[0]-arr[0]+1。
最后值得注意的是用树状数组的话题目中范围是0~n-1,出现0会死循环,因此arr[i]要自增1再操作。
树状数组代码(31ms):
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<sstream>
#include<cstring>
#include<cstdio>
#include<string>
#include<deque>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
using namespace std;
#define INF 0x3f3f3f3f
#define CLR(x,y) memset(x,y,sizeof(x))
#define LC(x) (x<<1)
#define RC(x) ((x<<1)+1)
#define MID(x,y) ((x+y)>>1)
typedef pair<int,int> pii;
typedef long long LL;
const double PI=acos(-1.0);
const int N=5010;
int T[N];
inline int lowbit(const int &n)
{
return (n&-n);
}
void add(int k,int val)
{
while (k<N)
{
T[k]+=val;
k+=lowbit(k);
}
}
int getsum(int k)
{
int r=0;
while (k)
{
r+=T[k];
k-=lowbit(k);
}
return r;
}
int arr[N];
int main(void)
{
int n,i,j;
while (~scanf("%d",&n))
{
CLR(arr,0);
CLR(T,0);
int sum=0;
for (i=1; i<=n; ++i)
{
scanf("%d",&arr[i]);
++arr[i];
sum+=(getsum(n)-getsum(arr[i]));
add(arr[i],1);
}
int minm=INF;
for (i=1; i<=n; ++i)
{
sum=sum+(n-arr[i])-arr[i]-1);
if(sum<minm)
minm=sum;
}
printf("%d\n",minm);
}
return 0;
}
线段树代码 (62ms):
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<sstream>
#include<cstring>
#include<cstdio>
#include<string>
#include<deque>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
using namespace std;
#define INF 0x3f3f3f3f
#define CLR(x,y) memset(x,y,sizeof(x))
#define LC(x) (x<<1)
#define RC(x) ((x<<1)+1)
#define MID(x,y) ((x+y)>>1)
typedef pair<int,int> pii;
typedef long long LL;
const double PI=acos(-1.0);
const int N=5010;
struct info
{
int l,r,mid;
int sum;
}T[N<<2];
void pushup(int k)
{
T[k].sum=T[LC(k)].sum+T[RC(k)].sum;
};
void build(int k,int l,int r)
{
T[k].sum=0;
T[k].l=l;
T[k].r=r;
T[k].mid=MID(l,r);
if(l==r)
return ;
build(LC(k),l,T[k].mid);
build(RC(k),T[k].mid+1,r);
//pushup(k);
}
void update(int k,int x,int val)
{
if(T[k].l==T[k].r&&T[k].l==x)
T[k].sum+=val;
else
{
if(x<=T[k].mid)
update(LC(k),x,val);
else
update(RC(k),x,val);
pushup(k);
}
}
int range_query(int k,int l,int r)
{
if(l<=T[k].l&&r>=T[k].r)
return T[k].sum;
else
{
if(r<=T[k].mid)
return range_query(LC(k),l,r);
else if(l>T[k].mid)
return range_query(RC(k),l,r);
else
return range_query(LC(k),l,T[k].mid)+range_query(RC(k),T[k].mid+1,r);
}
}
int arr[N];
int Scan()
{
int res=0,ch,flag=0;
if((ch=getchar())=='-')
flag=1;
else if(ch>='0'&&ch<='9')
res=ch-'0';
while((ch=getchar())>='0'&&ch<='9')
res=res*10+ch-'0';
return flag?-res:res;
}
int main(void)
{
int n,i,j;
while (~scanf("%d",&n))
{
int sum=0,minm=INF;
build(1,0,N);
for (i=0; i<n; ++i)
{
arr[i]=Scan();
sum+=range_query(1,arr[i]+1,N);
update(1,arr[i],1);
}
for (i=0; i<n; ++i)
{
sum=sum+((n-1)-arr[i])-arr[i];
if(sum<minm)
minm=sum;
}
printf("%d\n",minm);
}
return 0;
}
HDU 1394 Minimum Inversion Number(线段树/树状数组求逆序数)的更多相关文章
- HDU.1394 Minimum Inversion Number (线段树 单点更新 区间求和 逆序对)
HDU.1394 Minimum Inversion Number (线段树 单点更新 区间求和 逆序对) 题意分析 给出n个数的序列,a1,a2,a3--an,ai∈[0,n-1],求环序列中逆序对 ...
- [HDU] 1394 Minimum Inversion Number [线段树求逆序数]
Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java ...
- HDU 1394 Minimum Inversion Number 线段树
题目: http://acm.hdu.edu.cn/showproblem.php?pid=1394 没看到多组输入,WA了一万次...... 其实很简单,有人暴力过得,我感觉归并排序.二叉排序树求逆 ...
- hdu - 1394 Minimum Inversion Number(线段树水题)
http://acm.hdu.edu.cn/showproblem.php?pid=1394 很基础的线段树. 先查询在更新,如果后面的数比前面的数小肯定会查询到前面已经更新过的值,这时候返回的sum ...
- HDU 1394 Minimum Inversion Number(线段树 或 树状数组)
题目大意:给出从 0 到 n-1 的整数序列,A0,A1,A2...An-1.可将该序列的前m( 0 <= m < n )个数移到后面去,组成其他的序列,例如当 m=2 时,得到序列 A2 ...
- HDU 1394 Minimum Inversion Number(线段树求最小逆序数对)
HDU 1394 Minimum Inversion Number(线段树求最小逆序数对) ACM 题目地址:HDU 1394 Minimum Inversion Number 题意: 给一个序列由 ...
- hdu 5147 Sequence II (树状数组 求逆序数)
题目链接 Sequence II Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- poj 2299 Ultra-QuickSort(树状数组求逆序数)
链接:http://poj.org/problem?id=2299 题意:给出n个数,求将这n个数从小到大排序,求使用快排的需要交换的次数. 分析:由快排的性质很容易发现,只需要求每个数的逆序数累加起 ...
- SGU180 Inversions(树状数组求逆序数)
题目: 思路:先离散化数据然后树状数组搞一下求逆序数. 离散化的方法:https://blog.csdn.net/gokou_ruri/article/details/7723378 自己对用树状数组 ...
- HDU 1394 Minimum Inversion Number ( 树状数组求逆序数 )
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 Minimum Inversion Number ...
随机推荐
- ssm操作控制台输出sql语句 log4j.properties
# Configures Log4j for Tomcat and Sakai # use "A" for log in with catalina.out (actually s ...
- docke跨主机通信之gre隧道
GRE简介 GRE可以对网络层的任何协议来进行封装,类似LVS的IPIP协议,在原有的数据报上增加GRE协议数据报.然后在网络上传输,到达对端后,解开GRE数据报头,得到真实的数据报.其中的mac地址 ...
- css3学习总结2--CSS3圆角边框
绘制一个圆角边框的示例 .div{ border: solid 5px blue; border-radius: 20px; -moz-border-radius:20px; -o-border-ra ...
- Ubuntu进不去,显示error:unknown filesystem (最简单解决方案总结)
error filesysterm:文件系统错误 grub rescue:是让你拯救grub,就是你的grub坏了,引导程序坏了 要安装盘?要重装?No…… 只要几行命令就ok了 是的,这是我昨天亲自 ...
- 幂运算(codevs 2541)
题目描述 Description 从m开始,我们只需要6次运算就可以计算出m31: m2=m×m,m4=m2×m2,m8=m4×m4,m16=m8×m8,m32=m16×m16,m31=m32÷m. ...
- Unix系统编程_cha11.6_线程同步
#include <stdio.h>#include <pthread.h>#include <stdlib.h> #define NHASH 29#define ...
- decltype
在C++中,decltype作为操作符,用于查询表达式的数据类型.decltype在C++11标准制定时引入,主要是为泛型编程而设计,以解决泛型编程中,由于有些类型由模板参数决定,而难以(甚至不可能) ...
- fuser命令小结
前提 linux环境下,当使用umount命令卸载挂载点时,会遇到“device is busy”提示,这时fuser就能查出谁在使用这个资源;当然umount –lf [挂载点] 也可以强制卸载 ...
- Java使用代理Proxy访问网络及其验证
在Java的网络编程中,有时候内网服务器需要访问外网的网络资源,这时候就需要使用代理. 设置代理(Proxy)可以有两种方式: 1.通过设置系统属性(System.setPropery(String ...
- CI中PHP写法规范(不断更新)
1.类名首字母大写,多个单词用下划线连接,首字母小写是无效的 举例: class CI_Model 2.routes路由配置中的右侧在配置类名和方法名的时候都是小写,如果大写可能会出现404找不到的错 ...