Hdu 1394 Minimum Inversion Number
来源:互联网 发布:java 流程图框架 编辑:程序博客网 时间:2024/06/06 19:03
题意:输入n,下面给出n个数,分别是0-n,顺序不定,可以通过对序列进行移动,每次移动把最前面的数移到后面,问通过移动形成的序列,使得得到的逆序数最少
思路:这题的特殊性方便了我们去寻找最小值。现在假设我们知道了原序列的逆序数是first,那么每次移动后怎么算出新的逆序数呢?因为每次都只是移动头元素,假设头元素为x,那么可以知道由x产生的逆序对的个数为x,因为有x个数小于它(0,1,2……x-1),如果将它放到了末尾,那么这x个逆序对将会消失。同样地,整个序列中有(n-1-x)个元素大于x,那么x移到了末尾,将产生(n-1-x)个新的逆序对(这些逆序对分别为(x+1,x),(x+2,x),(x+3,x)……(n-1,x))。因此可以递推地解决这个问题。如果知道了当前序列逆序数为sum,那么移动头元素后的逆序数将会是sum-x+(n-1-x)
那么接下来的问题就是求原序列的逆序数,得到它就可以知道所有其他序列的逆序数。用线段数解决
看列子:(某大神的解释)
先以区间[0,9]为根节点建立val都为0的线段树,
再看看怎样求下面序列的逆序数:
1 3 6 9 0 8 5 7 4 2
在线段树中插入1, 插入之前先询问区间[1,9]已插入的节点数(如果存在,必与1构成逆序) v1=0
在线段树中插入3, 插入之前先询问区间[3,9]已插入的节点数(如果存在,必与3构成逆序) v2=0
在线段树中插入6, 插入之前先询问区间[6,9]已插入的节点数(如果存在,必与6构成逆序) v3=0
在线段树中插入9, 插入之前先询问区间[9,9]已插入的节点数(如果存在,必与9构成逆序) v4=0
在线段树中插入0, 插入之前先询问区间[0,9]已插入的节点数(如果存在,必与0构成逆序) v5=4
在线段树中插入8, 插入之前先询问区间[8,9]已插入的节点数(如果存在,必与8构成逆序) v6=1
在线段树中插入5, 插入之前先询问区间[5,9]已插入的节点数(如果存在,必与5构成逆序) v7=3
在线段树中插入7, 插入之前先询问区间[7,9]已插入的节点数(如果存在,必与7构成逆序) v8=2
在线段树中插入4, 插入之前先询问区间[4,9]已插入的节点数(如果存在,必与4构成逆序) v9=5
在线段树中插入2, 插入之前先询问区间[2,9]已插入的节点数(如果存在,必与2构成逆序) v10=7
累加v1+……+v10 =22,这就是1 3 6 9 0 8 5 7 4 2的逆序数了.
其实就是统计一个区间内已经插入了多少个元素,也可以说成是区间求和(一个区间能达到的最大和就是该区间长度,现在的和就是已经插入在内的元素个数)
代码:
#include <iostream>#include <stdio.h>#include <cstring>#include <cmath>#include <vector>#include <algorithm>#include <map>#include <queue>#include <stack>#define lson l,mid,num<<1#define rson mid+1,r,num<<1|1using namespace std;const int M = 5005;int sum[M<<2];void PushUp(int num){ sum[num]=sum[num<<1]+sum[num<<1|1];}void build(int l,int r,int num){ if(l==r)return; int mid=(l+r)>>1; build(lson); build(rson);}void update(int p,int l,int r,int num){ if(l==r) { sum[num]++; return; } int mid=(l+r)>>1; if(p<=mid)update(p,lson); if(p>mid)update(p,rson); PushUp(num);}int query(int L,int R,int l,int r,int num){ if(L<=l && r<=R) return sum[num]; int mid=(l+r)>>1; int ans=0; if(L<=mid)ans+=query(L,R,lson); if(R>mid)ans+=query(L,R,rson); return ans;}int main(){ int n,x[M]; while(scanf("%d",&n)==1) { memset(sum,0,sizeof(sum)); int ans=0; build(0,n-1,1); for(int i=1; i<=n; i++) { scanf("%d",&x[i]); ans+=query(x[i],n-1,0,n-1,1); update(x[i],0,n-1,1); } int mmin=ans; for(int i=1;i<=n;i++) { ans=ans-x[i]+(n-x[i]-1); mmin=min(mmin,ans); } printf("%d\n",mmin); } return 0;}
- hdu 1394 Minimum Inversion Number
- hdu 1394 Minimum Inversion Number
- hdu 1394 Minimum Inversion Number
- HDU 1394 Minimum Inversion Number
- HDU-1394-Minimum Inversion Number
- HDU 1394 - Minimum Inversion Number
- HDU 1394 Minimum Inversion Number
- Hdu 1394 Minimum Inversion Number
- hdu 1394 Minimum Inversion Number
- hdu 1394 Minimum Inversion Number
- hdu 1394 Minimum Inversion Number
- hdu 1394 Minimum Inversion Number
- Hdu 1394 Minimum Inversion Number
- Minimum Inversion Number HDU 1394
- HDU 1394 Minimum Inversion Number
- HDU 1394 Minimum Inversion Number
- HDU 1394 Minimum Inversion Number
- Minimum Inversion Number----hdu 1394
- UVa 10706 - Number Sequence
- 大学毕业时的我-现在的我
- Android sdk manager 显示 Done loading packages 无法继续下载
- UVA 639 Don't Get Rooked
- hdu 1106 排序
- Hdu 1394 Minimum Inversion Number
- HDU 3177
- HDU 1358Period(KMP周期串)
- JavaSE基础之Java语言(命令行简介)
- hdu 1999 不可摸数
- C语言popen创建管道文件循环执行shell命令
- 一颗完全二叉树,求其结点个数
- 时间日期的转换
- Lua语法入门