hdu 1394 Minimum Inversion Number || ZOJ Monthly, January 2003 || 线段树 + 逆序数

来源:互联网 发布:教人做甜品的软件 编辑:程序博客网 时间:2024/06/05 15:03

hdu 1394 Minimum Inversion Number 请戳

  1. 题意:
    给长度为 n 的数组 A(0 <= A[i] <= n - 1)。
    进行 n - 1 次后移操作,每次将排在第一个的元素移到最后那个元素后面。
    没次数组A都有一个逆序数,求最小的逆序数。

  2. 思路:
    线段树计算逆序数,然后所有逆序数都可以递推出来,取最小的即可。
    去年作死都没想通为什么线段树能够写求出逆序数,今天看了下。。。居然秒懂。(那么问题来了!我去年干啥去了?)

  3. 复杂度:
    时间复杂度:O(n * log(n))
    空间复杂度:O(4 * n)

  4. 代码:

/* ***********************************************Author        :IlovezilianCreated Time  :2015/9/4 0:57:03File Name     :seg_tree_2.cpp************************************************ */#include <bits/stdc++.h>#define INF 0x7fffffffusing namespace std;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1const int N = 0,maxn = 5555, mod = 1e9+7;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 update(int p, int l, int r, int rt){    if(l == r)    {        sum[rt] ++;        return;    }    int m = (l + r) >> 1;    if(p <= m) update(p, lson);    else update(p, rson);    pushup(rt);}int query(int L, int R, int l, int r, int rt){    if(L <= l && r <= R)    {        return sum[rt];    }    int m = (l + r) >> 1, ret = 0;    if(L <= m) ret += query(L, R, lson);    if(R > m) ret += query(L, R, rson);    return ret;}int x[maxn];void solve(){    int n;    while(~scanf("%d", &n))    {        build(0, n - 1, 1);        int sum = 0;        for(int i = 0; i < n; i ++)        {            scanf("%d", x + i);            sum += query(x[i], n - 1, 0, n - 1, 1); //逆序数就是每次求和。            update(x[i], 0, n - 1, 1);//然后更新        }        int ret = sum;        for(int i = 0; i < n; i ++)        {            sum += n - x[i] - x[i] - 1; //这个递推有意思            ret = min(ret, sum);        }        printf("%d\n", ret);    }}int main(){    //freopen("","r",stdin);    //freopen("","w",stdout);    solve();    return 0;}
0 0
原创粉丝点击