hdu-1394(线段树&逆序数的性质和求法)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394
题目大意:
给出一个序列,一对逆序数就是满足i<j&&a[i]>a[j]条件的一对数字。
每次将a数组的最后一个数放到数组的第一位上,原数组向后移动一位,得到一个新的序列,
求这些序列中最小的逆序数。(每个数都在0-n-1范围内)
求解思路:
(1)逆序数的性质:一个序列第i次循环的逆序数Pi=P(i-1)+(n-1-a[i])-a[i]。
(2)可以通过暴力求解,每次找最小值就行了。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = ;
const int INF = ;
int a[maxn];
int main(void)
{
int mi,cnt,i,j,num,n;
while(~scanf("%d",&n))
{
memset(a,,sizeof(a));
for(i=;i<n;i++) scanf("%d",&a[i]);
mi=INF;cnt=;
for(i=;i<n;i++)
for(j=i+;j<n;j++)
if(a[i]>a[j]) cnt++;
if(mi>cnt) mi=cnt;
for(i=;i<n;i++)
{
cnt=cnt+(n--a[i])-a[i];
if(mi>cnt) mi=cnt;
}
printf("%d\n",mi);
}
return ;
}
(3)线段树做法:
先初始化线段树都为0,然后输入每个数,每个数字+1,即改为1-n区间,判断b[i]+1到n区间内有无数字,有的话逆序数就+1
然后再更新节点b[i]表示这个节点被访问过了。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = ;
const int INF = ;
int a[maxn<<],b[maxn];
void pushup(int x)
{
a[x]=a[x*]+a[x*+];
}
void build(int x,int l,int r)
{
if(l==r)
{
a[x]=;return ;
}
int mid=(l+r)/;
build(x*,l,mid);
build(x*+,mid+,r);
pushup(x);
}
void update(int x,int l,int r,int pos)
{
if(l==r)
{
a[x]++;return ;
}
int mid=(l+r)/;
if(pos<=mid) update(x*,l,mid,pos);
if(pos>mid) update(x*+,mid+,r,pos);
pushup(x);
}
int query(int x,int l,int r,int A,int B)
{
if(A<=l&&r<=B) return a[x];
int mid=(l+r)/,ans=;
if(A<=mid) ans+=query(x*,l,mid,A,B);
if(B>mid) ans+=query(x*+,mid+,r,A,B);
return ans;
}
int main(void)
{
int n,i,ans,mi;
while(~scanf("%d",&n))
{
memset(a,,sizeof(a));
memset(b,,sizeof(b));
build(,,n);
ans=;mi=INF;
for(i=;i<=n;i++)
{
scanf("%d",&b[i]);
b[i]++;
ans+=query(,,n,b[i]+,n);
update(,,n,b[i]);
}
if(mi>ans) mi=ans;
for(i=;i<n;i++)
{
ans=ans+(n-b[i]+)-b[i];
if(mi>ans) mi=ans;
}
printf("%d\n",mi);
}
return ;
}
(4)归并排序做法
归并排序时,当a[j]>a[i]时,每次记录tmp+=(mid-i+1),最终求出的tmp就是这个序列的逆序数。
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn = ;
int a[maxn],b[maxn],temp[maxn],tmp;
void Merge_Sort(int l,int r,int mid)
{
int pos=,i=l,j=mid+;
while(i<=mid&&j<=r)
{
if(a[i]>a[j]) tmp+=(mid+-i),temp[pos++]=a[j++];
else temp[pos++]=a[i++];
}
while(i<=mid) temp[pos++]=a[i++];
while(j<=r) temp[pos++]=a[j++];
for(i=;i<pos;i++) a[i+l]=temp[i];
}
void Merge(int l,int r)
{
if(l==r) return ;
int mid=(l+r)/;
Merge(l,mid);
Merge(mid+,r);
Merge_Sort(l,r,mid);
}
int main(void)
{
int n,ans,i;
while(~scanf("%d",&n))
{
for(i=;i<n;i++)
{
scanf("%d",&a[i]);b[i]=a[i];
}
tmp=;ans=;
Merge(,n-);
ans=tmp;
for(i=;i<n;i++){
tmp=tmp+n--b[i]*;
if(ans>tmp) ans=tmp;
}
printf("%d\n",ans);
}
return ;
}
hdu-1394(线段树&逆序数的性质和求法)的更多相关文章
- hdu 1394(线段树) 最小逆序数
http://acm.hdu.edu.cn/showproblem.php?pid=1394 给出一列数组,数组里的数都是从0到n-1的,在依次把第一个数放到最后一位的过程中求最小的逆序数 线段树的应 ...
- hdu 1394 (线段树求逆序数)
<题目链接> 题意描述: 给你一个有0--n-1数字组成的序列,然后进行这样的操作,每次将最前面一个元素放到最后面去会得到一个序列,那么这样就形成了n个序列,那么每个序列都有一个逆序数,找 ...
- hdu 1394 线段树计算逆序数
线段树计算逆序数的原理: 用线段树来统计已插入的数的个数(所以要保证最大的那个数不能太大,否则数组都开不了),然后每插入一个数,就查询比插入的数大的个数,累加即可. 这个题还有一个特点就是,题目给的是 ...
- HDU 1394 线段树求逆序对
Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java ...
- HDU 1394 线段树or 树状数组~
Minimum Inversion Number Description The inversion number of a given number sequence a1, a2, ..., an ...
- hdu 1394 线段树
Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java ...
- hdu 5877 线段树(2016 ACM/ICPC Asia Regional Dalian Online)
Weak Pair Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)Total ...
- hdu 3974 线段树 将树弄到区间上
Assign the task Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- hdu 3436 线段树 一顿操作
Queue-jumpers Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) To ...
随机推荐
- C++ 智能指针shared_ptr的实现
#include <memory> #include <iostream> using namespace std; template<typename T> cl ...
- stark组件之注册【模仿Django的admin】
一.先看下django的admin是如何实现注册功能 首先导入admin这个对象和我们的model模块 from django.contrib import admin # Register your ...
- 不通过调用__Init__来创建实例
老样子,抛出个问题,我们想要创建一个实例,但是由于某些原因想绕过__init__方法,用别的方式来进行创建. 举个栗子 小贱贱反序列化数据,或者说实现一个类方法将其作为备选的构造函数,都属于这种情况. ...
- Java11-java基础语法(十)类设计综合案例
Java11-java语法基础(十)类设计综合案例 一.类综合设计方法 1.类设计步骤 (1)分析数据成员 (2)分析成员方法和构造方法 (3)画出类图 (4)编码测试 2.具体问题 1)分析数据成员 ...
- Linux日志文件分割
经常有这样的情况,日志文件或者数据文件会变得很庞大,那么每次对这些目标文件的访问或者修改就会变得极其耗时.因而引发一些性能问题,但是如果对这些目标文件进行分割,限定其大小,那么每次的访问或者修改就会变 ...
- linux命令学习之:cd
cd命令用来切换工作目录至dirname. 其中dirName表示法可为绝对路径或相对路径.若目录名称省略,则变换至使用者的home directory(也就是刚login时所在的目录).另外,~也表 ...
- Java面试基础知识(1)
1.final, finally, finalize的区别 final:修饰符(关键字)如果一个类被声明为final,没有子类也不能被继承.因此一个类不能既被声明为 abstract的,又被声明为fi ...
- vue解决遮罩层滚动方法
vue 遮罩层阻止默认滚动事件 在写移动端页面的时候,弹出遮罩层后,我们仍然可以滚动页面. vue中提供 @touchmove.prevent 方法可以完美解决这个问题 <div class=& ...
- 【WH】MVC数据分页扩展类
public static class QueryableExtensions { #region 内存分页 /// <summary> /// 返回对象分页列表 /// </sum ...
- Varnish 入门
本文将介绍 varnish 的工作流程,安装以及 varnish 的配置三个方面的内容.首先简单的介绍 varnish 以及其工作流程,大概了解其内部原理,然后介绍了 varnish 的安装方法,最后 ...