用归并排序或树状数组求逆序对数量 poj2299
题目链接:https://vjudge.net/problem/POJ-2299
推荐讲解树状数组的博客:https://blog.csdn.net/int64ago/article/details/7429868
题目意思就是让我们把无序的一些数字经过相邻数字间两两交换,最后变成不递减的数字。我们要求出最少要交换的次数。
逆序对(百度的):对于一个包含N个非负整数的数组,A[1..n],A[1..n],如果有i < j,且A[ i ]>A[ j ],则称(A[ i] ,A[ j] )为数组A中的一个逆序对。
了解了一下树状数组就过来做这题了,一开始用map容器,一直TLE,后面看了论坛,发现不用map容器编号就可以过,并且还可以用归并排序来写,这两种方法都可以用来求逆序对数量。
树状数组:
因为数字最大可以达到999999999,我们用数组是存不下来的,所以我们要给每一个数字编号,
假设现在就是 9 1 0 5 4
那么我给它们编一个号码就是 1 2 3 4 5 状态一
我们要把它们用两两交换的方法来进行排序,排序之后就是 0 1 4 5 9
对应的编号就是 3 2 5 4 1 状态二
那现在问题就可以看成我们把编号1到5从状态一用相邻数字交换点的方法变换到状态二,它等同于从状态二变换到状态一,我们现在就讨论从状态二变换到状态一需要的步数就可以了,那么我们看状态二,从左到右枚举每一个数字,每次加上它前面比他大的数字的数量(就相当于把他交换到所有比他大的数字前面),这个用树状数组里面求区间和的操作就可以了,假设现在编号是k,那么加的数量就是函数sum(n)-sum(k)。恩,没了。
代码:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<vector>
#include<set>
#include<cstdio>
#include<string>
#include<deque>
using namespace std;
typedef long long LL;
#define eps 1e-8
#define INF 0x3f3f3f3f
#define maxn 500005
struct node{
int index,value;//编号和一开始的值
}a[maxn];
LL b[maxn],ans;//要用long long
int n;
bool cmp(node s1,node s2){
return s1.value<s2.value;
}
int lowbit(int x){
return x&(-x);
}
LL sum(int x){
LL ans=;
while(x>){
ans+=b[x];
x-=lowbit(x);
}
return ans;
}
void add(int x){
while(x<maxn){
b[x]++;
x+=lowbit(x);
}
}
int main()
{
while(scanf("%d",&n)&&n){
ans=;
memset(b,,sizeof(b));
for(int i=;i<=n;i++){//编号我们从1开始,防止后面单点修改的时候死循环
scanf("%d",&a[i].value);
a[i].index=i;
}
sort(a+,a+n+,cmp);
for(int i=;i<=n;i++){
ans+=sum(n)-sum(a[i].index);
add(a[i].index);
}
printf("%lld\n",ans);
}
return ;
}
归并排序:
用归并排序也写了一下,复习了一下归并排序,开森。
归并排序用了二分的思想,先把一个大区间不断划分成两个小区间,知道不能划分,然后回溯的时候进行区间合并,在我们合并的时候就可以顺带求出逆序对的数量了,额,如果不会归并排序可以百度一下下。我们看下面的一个例子:
假设现在有了两个较小的排好了序的区间分别是2 6 9和 3 5 10。根据归并排序的原理,事实上他们在整个数组上面是连续的,就是
2 6 9 3 5 10这样排的,现在我们要和并他们,那么首先我们把两个区间里面最小的数字拿出来比较一下,2<3,那么2在第一个位置,然后6和3比较,6>3,那么我们要把3放在6的前面,那么我们要把3移几位呢,在连续的2 6 9 3 5 10 里面我们把3移到6前面是要经过6和9的,那么就是要移两位,那么这六个数字就变成了2 3 6 9 5 10,同理,接下来6>5,我们还是要把5移到6前面,那么还是2步,最后我们总结出一个规律,就是左边区间的a[i]和右边区间的a[j]相比较 ,如果a[i]<=a[j],那么它们本来就是从小到大的,我们不移,如果是a[i]>a[j]那么我们需要移的数目就是mid-i+1,事实上面就是左边区间剩余数字的数目。
代码:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<vector>
#include<set>
#include<cstdio>
#include<string>
#include<deque>
using namespace std;
typedef long long LL;
#define eps 1e-8
#define INF 0x3f3f3f3f
#define maxn 500005
LL ans,a[maxn],b[maxn],n;
void marge(int left,int mid,int right){
int l=left;
int r=mid+;
int cnt=l;
while(l<=mid&&r<=right){
if(a[l]<=a[r])
b[cnt++]=a[l++];
else{
b[cnt++]=a[r++];
ans+=mid-l+;//在这里加一下就可以了
}
}
while(l<=mid) b[cnt++]=a[l++];
while(r<=right) b[cnt++]=a[r++];
for(int i=left;i<=right;i++)
a[i]=b[i];
}
void marge_sort(int l,int r){
if(l==r){
return;
}
int mid=(l+r)/;
marge_sort(l,mid);
marge_sort(mid+,r);
marge(l,mid,r);
}
int main()
{
while(scanf("%lld",&n)&&n){
ans=;
for(int i=;i<n;i++){
scanf("%lld",&a[i]);
}
marge_sort(,n-);
printf("%lld\n",ans);
}
return ;
}
用归并排序或树状数组求逆序对数量 poj2299的更多相关文章
- POJ2299Ultra-QuickSort(归并排序 + 树状数组求逆序对)
树状数组求逆序对 转载http://www.cnblogs.com/shenshuyang/archive/2012/07/14/2591859.html 转载: 树状数组,具体的说是 离散化+树 ...
- [NOIP2013提高&洛谷P1966]火柴排队 题解(树状数组求逆序对)
[NOIP2013提高&洛谷P1966]火柴排队 Description 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相 ...
- [NOI导刊2010提高&洛谷P1774]最接近神的人 题解(树状数组求逆序对)
[NOI导刊2010提高&洛谷P1774]最接近神的人 Description 破解了符文之语,小FF开启了通往地下的道路.当他走到最底层时,发现正前方有一扇巨石门,门上雕刻着一幅古代人进行某 ...
- 【bzoj2789】[Poi2012]Letters 树状数组求逆序对
题目描述 给出两个长度相同且由大写英文字母组成的字符串A.B,保证A和B中每种字母出现的次数相同. 现在每次可以交换A中相邻两个字符,求最少需要交换多少次可以使得A变成B. 输入 第一行一个正整数n ...
- “浪潮杯”第九届山东省ACM大学生程序设计竞赛(重现赛)E.sequence(树状数组求逆序对(划掉))
传送门 E.sequence •题意 定义序列 p 中的 "good",只要 i 之前存在 pj < pi,那么,pi就是 "good": 求删除一个数, ...
- 2021.12.10 P5041 [HAOI2009]求回文串(树状数组求逆序对)
2021.12.10 P5041 [HAOI2009]求回文串(树状数组求逆序对) https://www.luogu.com.cn/problem/P5041 题意: 给一个字符串 \(S\) ,每 ...
- NOIP 2013 洛谷P1966 火柴排队 (树状数组求逆序对)
对于a[],b[]两个数组,我们应选取其中一个为基准,再运用树状数组求逆序对的方法就行了. 大佬博客:https://www.cnblogs.com/luckyblock/p/11482130.htm ...
- poj3067 Japan 树状数组求逆序对
题目链接:http://poj.org/problem?id=3067 题目就是让我们求连线后交点的个数 很容易想到将左端点从小到大排序,如果左端点相同则右端点从小到大排序 那么答案即为逆序对的个数 ...
- 牛客练习赛38 D 题 出题人的手环 (离散化+树状数组求逆序对+前缀和)
链接:https://ac.nowcoder.com/acm/contest/358/D来源:牛客网 出题人的手环 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 524288K,其他 ...
随机推荐
- centos下配置maven编译环境
版本centos6jdk1.7findbugs-3.0.1maven-3.0.5protobuf-2.6.0安装yum install lzo-devel zlib-devel gcc gcc-c++ ...
- Arch Linux 独特的包管理器相关名词解释及用法对照
https://wiki.archlinux.org/index.php/PacmanPacman包管理器是Arch Linux的主要特色之一.它结合了简单的二进制包格式和易于使用的构建系统.pacm ...
- c++ 快速读入输出
1. 读入优化 C++中有一个函数:getchar() ,用于读入字符,那么这跟读入整数有什么关系呢? 其实,经过类似高精度的处理,就可以实现类型转换啦! 下面是正负数读入优化模板: #include ...
- sh - 脚本学习 启动/停止/重启/部署jetty crontab
===============jettytest.sh ====================== #!/bin/shjettysh_path=/usr/local/jetty/bin/jetty. ...
- 用变量替换指定的字符串,sed: -e 表达式 #1, 字符 29: “s”的未知选项
在shell脚本里,使用sed,然后用变量替换指定的字符串,一直出现这个错误:但是单独运行在外面可以 把分隔符/替换成#就可以: sed "s#revision=.*#revision=$s ...
- 概念:dependency injection, IOC, vs callback
callback function as a dependency of the object that it is being passed into. DI is the process of p ...
- Fiddler: 如何抓取HTTPS协议的网页
作者:韦玮 转载请注明出处 Fiddler默认只能抓取HTTP协议的网页,不能抓取HTTPS协议的网页,而我们很多时候,都需要抓HTTPS协议的网页,比如抓淘宝数据等.今天,韦玮老师会为大家讲解如何 ...
- 【spring】之基于注解@ComponentScan的一些使用
基于xml形式ComponentScan的使用如下 <context:component-scan base-package="com.luna" use-default-f ...
- property用法
用法一 class Test(object): def __init__(self): self.__Num = 100 def setNum(self,Num): print("---se ...
- day28元类与异常查找
元类与异常处理1. 什么是异常处理 异常是错误发生的信号,一旦程序出错就会产生一个异常,如果该异常 没有被应用程序处理,那么该异常就会抛出来,程序的执行也随之终止 异常包含三个部分: ...