zoukankan      html  css  js  c++  java
  • 线段数 --- (单点更新、求逆序对)

    Minimum Inversion Number

    Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u

     

    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 Input

    10
    1 3 6 9 0 8 5 7 4 2
     

     

    Sample Output

     

    16
     

    用线段树求逆序对的水题,维护的是区间内整数的个数,每次插入 x 时,查询在 x 的前面比小的数的个数,并计算出比 x 大的数的个数 cnt[x] ,最后将 cnt 累加,即为逆序数;

    将队首的数放到队尾后逆序数改变:n-1-a[i], a[i] 为原始序列中第 i 个数的值;

    # include <stdio.h>
    # include <string.h>
    # define N 50010
    
    int n, D;
    int sum[4 * N], cnt[N], a[N];
    
    void update(int i)
    {
        for (; i ^ 1; i >>= 1)
        {
            sum[i >> 1] = sum[i] + sum[i ^ 1];
        }
    }
    
    int query(int s, int t)
    {
        int ret;
        
        ret = 0;
        s += D-1, t += D+1;
        for ( ; s ^ t ^ 1; s >>= 1, t >>= 1)
        {
            if (~s & 0x1) ret += sum[s+1];
            if ( t & 0x1) ret += sum[t-1];
        }
    
        return ret;
    }
    
    void init(void)
    {
        int i;
        
        for (D = 1; D < n+2; D <<= 1) ;
        
        memset(sum, 0, sizeof(sum[0])*2*D+5);
        memset(cnt, 0, sizeof(cnt[0])*n+5);
        memset(a, 0, sizeof(a[0])*n+5);
        
        for (i = 1; i <= n; ++i)
        {
            scanf("%d", &a[i]);
            cnt[i] = i - 1 - query(0, a[i]);
            ++sum[a[i]+D], update(a[i]+D);
        }
    }
    
    void solve(void)
    {
        int rev, i, min;
    
        rev = 0;
        for (i = 1; i <= n; ++i)
        {
            rev += cnt[i];
        }
        min = rev;
        for (i = 1; i <= n; ++i)
        {
            rev += n-1-2*a[i];
            if (min > rev) min = rev;
        }
        printf("%d
    ", min);
    }
    
    int main()
    {    
        while (~scanf("%d", &n))
        {
            init();
            solve();
        }
    
        return 0;
    }

    树状数组实现:

    #include<stdio.h>
    #include<string.h>
    #define min(a,b)(a)<(b)?(a):(b);
    int v[5002];
    int l[5002];
    int n;
    int lowbit(int x)
    {
        return (x)&(-x);
    }
    void update(int pos)
    {
        while(pos<=n)
        {
            l[pos]+=1;
            pos+=lowbit(pos);
        }
    }
    int getsum(int x)
    {
        int sum=0;
        while(x>0)
        {
            sum+=l[x];
            x-=lowbit(x);
        }
        return sum;
    }
    int main()
    {
        int res,p,i,sum;
        while(scanf("%d",&n)!=EOF)
        {
            sum=0;
            memset(l,0,sizeof(l));
            for(i=0;i<n;i++)
            {
                scanf("%d",&v[i]);
                v[i]++;
                sum+=(getsum(n)-getsum(v[i]));
                update(v[i]);
            }
            res=sum;
            for(i=0;i<n;i++)
            {
                sum+=n-v[i]-v[i]+1;
                res=min(res,sum);
            }
            printf("%d
    ",res);
        }
        return 0;
    }

    归并排序实现:

    #include <stdio.h>
    long long left[100001], right[100001];
    long long count;
    void merge(long long* a, long long p, long long q, long long r)
    {
        long long i, j, k, n1, n2;
        n1 = q-p+1;
        n2 = r-q;
        for (i=0; i<n1; ++i)
        {
            left[i] = a[p+i];
        }
        for (i=0; i<n2; ++i)
        {
            right[i] = a[q+i+1];
        }
        left[n1] = right[n2] =2147483647;
    
        i = j = 0;
        for (k=p; k<=r; ++k)
        {
            if (left[i] <= right[j])
            {
                a[k] = left[i];
                i++;
            }
            else
            {
                a[k] = right[j];
                j++;
                count += n1-i;
            }
        }
        return;
    }
    
    void mergesort(long long* a, long long p, long long r)
    {
        long long q;
        if (p < r)
        {
            q = (p+r)/2;
            mergesort(a, p, q);
            mergesort(a, q+1, r);
            merge(a, p, q, r);
        }
        return ;
    }
    
    long long n,i, t, a[100001];
    int main()
    {
        while (scanf("%I64d", &n)!=EOF)
        {
            count = 0;
            for (i=0; i<n; ++i)
            {
                scanf("%I64d", &a[i]);
            }
            mergesort(a, 0, n-1);
            printf("%I64d
    ", count);
        }
    }

    对比了几种求逆序对的方法后,发现还是归并好用,既快代码又短.

     

  • 相关阅读:
    《深度学习推荐系统中各类流行的Embedding方法(上)》
    《替代梯度下降——基于极大值原理的深度学习训练算法》&《加速对抗训练——YOPO算法浅析》
    《【炼丹技巧】功守道:NLP中的对抗训练 + PyTorch实现》
    《论文阅读:对抗训练(adversarial training)》
    《一文搞懂NLP中的对抗训练》
    CLOUD配置审批流发消息
    CLOUD财务成本核算
    K3CLOUDJOBPROCESS每分钟重启
    查看服务器日志
    数据规则列表加导入导出
  • 原文地址:https://www.cnblogs.com/crazyacking/p/3705415.html
Copyright © 2011-2022 走看看