HDU 1394 Minimum Inversion Number(最小逆序数/暴力 线段树 树状数组 归并排序)
题目链接: 传送门
Minimum Inversion Number
Time Limit: 1000MS Memory Limit: 32768 K
Description
The inversion number of a given number sequence a1, a2, ..., an is the number of pairs (ai, aj) that satisfy i < j and ai > aj.
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.
Input
The input consists of a number of test cases. Each case consists of two lines: the first line contains a positive integer n (n <= 5000); the next line contains a permutation of the n integers from 0 to n-1.
Output
For each case, output the minimum inversion number on a single line.
Sample Iutput
10
1 3 6 9 0 8 5 7 4 2
Sample Output
16
解题思路:
- 1、暴力
注意到输入的n个数是从0~n-1并且每次都把第一个数移到最后一个数,所以原来比它小的数(和它构成逆序)在移动之后就不是逆序了,而原来比它大的数>(不和它构成逆序)在移动之后就是逆序了,因此很容易推得每次减少的逆序数为n-1-a[i]每次增加的逆序数为a[i]- 2、线段树
首先先来看一个序列 6 1 2 7 3 4 8 5,此序列的逆序数为5+3+1=9。冒泡法可以直接枚举出逆序数,但是时间复杂度太高O(n^2)。冒泡排序的原理是枚举每一个数组,然后找出这个数后面有多少个数是小于这个数的,小于它逆序数+1。仔细想一下,如果我们不用枚举这个数后面的所有数,而是直接得到小于这个数的个数,那么效率将会大大提高。
总共有N个数,如何判断第i+1个数到最后一个数之间有多少个数小于第i个数呢?不妨假设有一个区间 [1,N],只需要判断区间[i+1,N]之间有多少个数小于第i个数。如果我们把总区间初始化为0,然后把第i个数之前出现过的数都在相应的区间把它的值定为1,那么问题就转换成了[i+1,N]值的总和。再仔细想一下,区间[1,i]的值+区间[i+1,N]的值=区间[1,N]的值(i已经标记为1),所以区间[i+1,N]值的总和等于N-[1,i]的值!因为总共有N个数,不是比它小就是比它(大或等于)。
现在问题已经转化成了区间问题,枚举每个数,然后查询这个数前面的区间值的总和,N-[1,i]即为逆序数。
暴力求解
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef __int64 LL;
int main()
{
int N;
while (~scanf("%d",&N))
{
int ans[5005] = {0};
int sum = 0,res;
for (int i = 0;i < N;i++)
{
scanf("%d",&ans[i]);
}
for (int i = 0;i < N;i++)
{
for (int j = i + 1;j < N;j++)
{
if (ans[i] > ans[j])
{
sum++;
}
}
}
res = sum;
for (int i = 0;i < N;i++)
{
sum += N - ans[i] - ans[i] - 1;
res = min(res,sum);
}
printf("%d\n",res);
}
return 0;
}
线段树
#include<cstdio>
#include<algorithm>
using namespace std;
#define lson l , m , rt << 1
#define rson m + 1, r , rt << 1 | 1
const int maxn = 5005;
int sum[maxn<<2];
void PushUp(int rt)
{
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void build(int l,int r,int rt)
{
sum[rt] = 0;
if (l == r) return;
int m = (l + r) >> 1;
build(lson);
build(rson);
}
void upd(int p,int l,int r,int rt)
{
if (l == r)
{
sum[rt]++;
return;
}
int m = (l + r) >> 1;
if (p <= m) upd(p,lson);
else upd(p,rson);
PushUp(rt);
}
int qry(int L,int R,int l,int r,int rt)
{
if (L <= l && r <= R)
{
return sum[rt];
}
int m = (l + r) >> 1;
int ret = 0;
if (L <= m) ret += qry(L,R,lson);
if (R > m) ret += qry(L,R,rson);
return ret;
}
int main()
{
int N;
while (~scanf("%d",&N))
{
int ans[maxn];
build(0,N - 1,1);
int sum = 0;
for (int i = 0; i < N;i++)
{
scanf("%d",&ans[i]);
sum += qry(ans[i],N - 1,0,N - 1,1);
upd(ans[i],0,N - 1,1);
}
int ret = sum;
for (int i = 0;i < N;i++)
{
sum += N - ans[i] - ans[i] - 1;
ret = min(ret,sum);
}
printf("%d\n",ret);
}
return 0;
}
树状数组
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 5005;
int c[maxn],N;
void upd(int i,int v)
{
while (i <= N)
{
c[i] += v;
i += i & -i;
}
}
int sum(int i)
{
int ret = 0;
while (i > 0)
{
ret += c[i];
i -= i & -i;
}
return ret;
}
int main()
{
while (~scanf("%d",&N))
{
int ans[maxn] = {0};
int res = 0,tmp;
memset(c,0,sizeof(c));
for (int i = 0;i < N;i++)
{
scanf("%d",&ans[i]);
res += sum(N) - sum(ans[i] + 1);
upd(ans[i] + 1,1);
}
tmp = res;
for (int i = 0;i < N;i++)
{
tmp -= ans[i];
tmp += N - ans[i] - 1;
res = min(tmp,res);
}
printf("%d\n",res);
}
return 0;
}
归并排序
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
const int maxn = 5005;
int sum;
void merge_array(int array[],int left,int mid,int right)
{
if (left >= right) return;
int i = left,j = mid + 1,k = 0;
int *p;
p = (int *)malloc((right - left + 1)*sizeof(int));
while (i <= mid && j <= right)
{
if (array[i] <= array[j])
{
p[k++] = array[i++];
}
else
{
p[k++] = array[j++];
sum += mid - i + 1; //[i-mid]序列就都能与a[j]构成逆序对,故:mid-i+1
}
}
while (i <= mid)
{
p[k++] = array[i++];
}
while (j <= right)
{
p[k++] = array[j++];
}
for (int i = 0;i < k;i++)
{
array[i+left] = p[i];
}
free(p);
}
void merge_sort(int array[],int left,int right)
{
if (left >= right) return;
int mid = (left + right)>>1;
merge_sort(array,left,mid);
merge_sort(array,mid + 1,right);
merge_array(array,left,mid,right);
}
int main()
{
int N;
while (~scanf("%d",&N))
{
int a[maxn],b[maxn],res;
sum = 0;
for (int i = 0;i < N;i++)
{
scanf("%d",&a[i]);
b[i] = a[i];
}
merge_sort(a,0,N - 1);
res = sum;
for (int i = 0;i < N;i++)
{
sum += N - b[i] - b[i] - 1;
res = min(res,sum);
}
printf("%d\n",res);
}
return 0;
}
HDU 1394 Minimum Inversion Number(最小逆序数/暴力 线段树 树状数组 归并排序)的更多相关文章
- HDU 1394 Minimum Inversion Number(最小逆序数 线段树)
Minimum Inversion Number [题目链接]Minimum Inversion Number [题目类型]最小逆序数 线段树 &题意: 求一个数列经过n次变换得到的数列其中的 ...
- HDU 1394.Minimum Inversion Number-最小逆序数-完全版线段树(单点增减、区间求和)
HDU1394.Minimum Inversion Number 这个题求最小逆序数,先建一个空的树,然后每输入一个值,就先查询一下,查询之后,更新线段树,然后遍历一遍,每次将第一个数放到最后之后,减 ...
- hdu1394 Minimum Inversion Number(最小逆序数)
Minimum Inversion Number Time Limit : 2000/1000ms (Java/Other) Memory Limit : 65536/32768K (Java/O ...
- HDU 1394 Minimum Inversion Number(线段树求最小逆序数对)
HDU 1394 Minimum Inversion Number(线段树求最小逆序数对) ACM 题目地址: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 ( 树状数组求逆序数 )
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 Minimum Inversion Number ...
- hdu 1394 Minimum Inversion Number 逆序数/树状数组
Minimum Inversion Number Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showprob ...
- 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(逆序数对) : 树状数组 O(nlogn)
http://acm.hdu.edu.cn/showproblem.php?pid=1394 //hdu 题目 Problem Description The inversion number ...
随机推荐
- 【python游戏编程之旅】第七篇---pygame中的冲突检测技术
本系列博客介绍以python+pygame库进行小游戏的开发.有写的不对之处还望各位海涵. 上一个博客我们一起学习了pygame中的Sprite模块和如何加载动画:http://www.cnblogs ...
- ArcEngine选中面要素样式修改
//只用前五行,可以直接将选中的面要素的颜色全部修改成红色,也就是填充颜色 IRgbColor pRgbColor= new RgbColor();; pRgbColor.Red = ; pRgbCo ...
- Unix 复制文件至指定目录
cp /gaps/log/20160504/bxdx_20160504.log.Z /home 将/gaps/log/20160504/bxdx_20160504.log.Z 文件复制到home路 ...
- 桔子浏览器|1M安装包|hao123专属浏览器
桔子浏览器是百度为好123打造的首页导航浏览器,体积小.为老年机上网提供便利. 免费下载:http://yunpan.cn/cmKbYXamEVUiY 访问密码 d270
- 什么是smarty?
什么是smarty? Smarty是一个使用PHP写出来的模板PHP模板引擎,由PHP.net官方提供 ,它提供了逻辑与外在内容的分离,简单的讲,目的就是要使用PHP程 序员同美工分离,使用的程序员改 ...
- HttpModule与HttpHandler详解
ASP.NET对请求处理的过程:当请求一个*.aspx文件的时候,这个请求会被inetinfo.exe进程截获,它判断文件的后缀(aspx)之后,将这个请求转交给 ASPNET_ISAPI.dll,A ...
- bootstarp风格的toggle效果分享
最近在写项目的时候想要一个这样的效果: 我知道这个效果在 flat-ui中有, 但是我又不想引用一整个flat-ui; 这个效果依赖html5的transition, 所以浏览器兼容成问题: 从fla ...
- 安全框架 SpringSecurity 和 Shiro 对比
突然再次很想理一下权限的事,但是实在不知道实际情况选哪个框架好,现在整理下网上的资料,做一下对比. 1.Spring-security 对spring 结合较好,如果项目用的springmvc ,使用 ...
- Echarts-画叠加柱状图,双折线图
导入echarts包 <script src='../scripts/libraries/echarts/echarts-all.js'></script> js如下 load ...
- jquery读取iframe子页面和父页面的处理
1. jquery 在iframe子页面获取父页面元素代码如下: $("#objid", parent.document) 2. jquery在父页面 获取iframe子页面的元素 ...