HDU 1394 Minimum Inversion Number 树状数组&&线段树

题目给了你一串序列,然后每次 把最后一个数提到最前面来,直到原来的第一个数到了最后一个,每次操作都会产生一个新的序列,这个序列具有一个逆序数的值,问最小的你逆序数的值为多少

逆序数么 最好想到的是树状数组,敲了一把很快,注意把握把最后一个数提上来对逆序数的影响即可,

#include<iostream>
#include<cstdio>
#include<list>
#include<algorithm>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<cmath>
#include<memory.h>
#include<set>
#include<cctype>

#define ll long long

#define LL __int64

#define eps 1e-8

#define inf 0xfffffff

//const LL INF = 1LL<<61;

using namespace std;

//vector<pair<int,int> > G;
//typedef pair<int,int > P;
//vector<pair<int,int> > ::iterator iter;
//
//map<ll,int >mp;
//map<ll,int >::iterator p;

int n;

int c[10000 + 5];

int num[10000 + 5];

void init() {
	memset(c,0,sizeof(c));
	memset(num,0,sizeof(num));
}

int lowbit(int x) {
	return x&(-x);
}

void add(int i,int val) {
	while(i <= n) {
		c[i] += val;
		i += lowbit(i);
	}
}

int get_sum(int i) {
	int sum = 0;
	while(i > 0) {
		sum += c[i];
		i -= lowbit(i);
	}
	return sum;
}

int main() {
	while(scanf("%d",&n) == 1) {
		init();

		int ans = 0;
		for(int i=1;i<=n;i++) {
			scanf("%d",&num[i]);
			num[i]++;
			add(num[i],1);
			ans += (i - get_sum(num[i]));
		}
		int minn = ans;
		for(int i=n;i>1;i--) {
			ans = ans + num[i] + num[i] - n - 1;
			minn = min(ans,minn);
		}
		printf("%d\n",minn);
	}
	return 0;
}

线段树:

#include<iostream>
#include<cstdio>
#include<list>
#include<algorithm>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<cmath>
#include<memory.h>
#include<set>
#include<cctype>

#define ll long long

#define LL __int64

#define eps 1e-8

#define inf 0xfffffff

//const LL INF = 1LL<<61;

using namespace std;

//vector<pair<int,int> > G;
//typedef pair<int,int > P;
//vector<pair<int,int> > ::iterator iter;
//
//map<ll,int >mp;
//map<ll,int >::iterator p;

const int N = 10000 + 5;

int num[N];

typedef struct Node {
    int a;
    int l,r;
};

Node tree[N * 4];

void init() {
    memset(tree,0,sizeof(tree));
    memset(num,0,sizeof(num));
}

void cal(int id) {
    tree[id].a = min(tree[id<<1].a,tree[id<<1|1].a);
}

void build(int l,int r,int id) {
    tree[id].l = l;
    tree[id].r = r;
    tree[id].a = 0;
    if(l == r) return ;
    int mid = (l + r)/2;
    build(l,mid,id<<1);
    build(mid+1,r,id<<1|1);
}

void updata(int w,int id) {
    if(tree[id]. l == w && tree[id].r == w) {
        tree[id].a = 1;return;
    }
    int mid = (tree[id].l + tree[id].r)/2;
    if(w <= mid) updata(w,id<<1);
    else updata(w,id<<1|1);
    tree[id].a = tree[id<<1].a + tree[id<<1|1].a;
}

int query(int l,int r,int id) {
    if(l <= tree[id].l && r >= tree[id].r)return tree[id].a;
    int mid = (tree[id].l + tree[id].r)/2;
    int ans1 = 0,ans2 = 0;
    if(l <= mid) ans1 = query(l,r,id<<1);
    if(r > mid) ans2 = query(l,r,id<<1|1);
    return ans1 + ans2;
}

int main() {

    int n;
    while(scanf("%d",&n) == 1) {
        init();
        build(1,n,1);
        int ans = 0;
        for(int i=0;i<n;i++) {
            scanf("%d",&num[i]);
            ans += query(num[i] + 1,n-1,1);
            updata(num[i],1);
        }
        int minn = ans;
        for(int i=0;i<n;i++) {
            ans = ans + n - 2 * num[i] - 1;
            minn = min(ans,minn);
        }
        printf("%d\n",minn);
    }
    return 0;
}

HDU 1394 Minimum Inversion Number 树状数组&&线段树

时间: 2024-10-13 23:52:35

HDU 1394 Minimum Inversion Number 树状数组&&线段树的相关文章

【Hdu】Minimum Inversion Number(逆序,线段树)

利用线段树在nlogn的时间复杂度内求一段数的逆序. 由于给的序列是由0 ~ n -1组成的,求出初始的逆序之后可以递推出移动之后的逆序数. #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; typedef long long LL; const int maxn = 5555; int tree[maxn <&l

hdu 1394 Minimum Inversion Number (裸树状数组 求逆序数)

题目链接 题意: 给一个n个数的序列a1, a2, ..., an ,这些数的范围是0-n-1, 可以把前面m个数移动到后面去,形成新序列: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)求这些序列中,逆序数最少的

HDU 1394 Minimum Inversion Number(线段树求最小逆序数对)

HDU 1394 Minimum Inversion Number(线段树求最小逆序数对) ACM 题目地址:HDU 1394 Minimum Inversion Number 题意: 给一个序列由[1,N]构成,可以通过旋转把第一个移动到最后一个. 问旋转后最小的逆序数对. 分析: 注意,序列是由[1,N]构成的,我们模拟下旋转,总的逆序数对会有规律的变化. 求出初始的逆序数对再循环一遍就行了. 至于求逆序数对,我以前用归并排序解过这道题:点这里. 不过由于数据范围是5000,所以完全可以用线

hdu 1394 Minimum Inversion Number 线段树 点更新

// hdu 1394 Minimum Inversion Number 线段树 点更新 // // 典型线段树的单点更新 // // 对于求逆序数,刚开始还真的是很年轻啊,裸的按照冒泡排序 // 求出最初始的逆序数,然后按照公式递推,结果就呵呵了 // // 发现大牛都是用线段树和树状数组之类的做的,而自己又在学 // 线段树,所以就敲了线段树. // // 线段树的节点保存一段区间( L,R )内0,1...n一共出现了多少个. // 因为每个数是0,1,2...n-1且没有重复的数字. /

HDU 1394 Minimum Inversion Number.(线段树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 ~~~~ 早起一发线段树,开心又快乐.这题暴力也能水过,同时线段树的效率也就体现的尤为明显了,看了大牛的博客,说是还可以用树状数组,点树和合并序列写,现在还不懂,留着以后在写吧. ~~~~ 大致题意:给定一个数字序列,同时由此可以得到n个序列, 要求从n个序列中找到逆序数最小的序列,输出最小逆序数. 首先介绍下逆序数的概念: 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面

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): 10853    Accepted Submission(s): 6676 Problem Description The inversion number of a given number sequence a1, a2, ..., a

HDU 1394 Minimum Inversion Number(线段树求逆序数)

题目地址:HDU 1394 这题可以用线段树来求逆序数. 这题的维护信息为每个数是否已经出现.每次输入后,都从该点的值到n-1进行查询,每次发现出现了一个数,由于是从该数的后面开始找的,这个数肯定是比该数大的.那就是一对逆序数,然后逆序数+1.最后求完所有的逆序数之后,剩下的就可以递推出来了.因为假如目前的第一个数是x,那当把他放到最后面的时候,少的逆序数是本来后面比他小的数的个数.多的逆序数就是放到后面后前面比他大的数的个数.因为所有数都是从0到n-1.所以比他小的数就是x,比他大的数就是n-

HDU 1394 Minimum Inversion Number(线段树求逆序对)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1394 解题报告:给出一个序列,求出这个序列的逆序数,然后依次将第一个数移动到最后一位,求在这个过程中,逆序数最小的序列的逆序数是多少? 这题有一个好处是输入的序列保证是0 到 n-1,所以不许要离散化,还有一个好处就是在计算在这个序列中比每个数大和小的数一共有多少个的时候可以在O(1)时间计算出来,一开始我没有意识到,还傻傻的用了两层for循环来每次都计算,当然这样果断TLE了.把一个数从第一个移

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): 9514    Accepted Submission(s): 5860 Problem Description The inversion number of a given number sequence a1, a2, ..., an