zoukankan      html  css  js  c++  java
  • 求逆序对

      1、逆序对的定义

      什么是逆序对呢?逆序对指的是在一个序列中,有x、y,满足x<y且a[x]>a[y],那么a[x]、a[y]就是一个逆序对。

      我们关于逆序对主要是求一个序列中逆序对的个数。

      2、如何求逆序对

      考虑朴素算法,对于每个x,y考虑一遍就好了,代码如下(其实我不太想打):

    #include<bits/stdc++.h>
    using namespace std;
    int n,a[1000001],ans,i,j;
    int main()
    {
        scanf("%d",&n);
        for (i=1;i<=n;i++)
            scanf("%d",&a[i]);
        ans=0;
        for (i=1;i<=n;i++)
            for (j=i;j<=n;j++)
            if (a[i]>a[j]) ans++;//判断大小关系
        pribntf("%d",ans);
        return 0;
    }

      明显的,这是一个O(n2)的算法,在一些n较大的题目中并不可用。

      有什么优化方法吗?

      归并排序(然而博主并没有学这玩意儿)

      树状数组(然而博主看不懂这玩意儿)

      主席树(然而博主并不认为你想用这玩意儿求逆序对)

      那就是线段树

      线段树怎么求逆序对呢?

      普通的线段树求的是[l,r]之间的元素之和,而我们这次是可以记录数值在[l,r]之间的数的个数,从后往前扫,边扫边加,这样就可以求出逆序对了(而且还可以求出每个点的逆序对个数等等)。

      注意要离散化。

      以下是代码:

    #include<bits/stdc++.h>
    using namespace std;
    long long z[2000001],l[2000001],r[2000001],n,d[500001],ans,i,cnt;
    struct cjy{
        long long z,q;
    }c[500001];
    bool cjj(cjy a,cjy b)//我不会告诉你为什么结构体类型名和判断函数名叫这个
    {
        return a.z<b.z;
    }
    inline void build(long long u,long long l1,long long r1)//线段树
    {
      l[u]=l1;
      r[u]=r1;
      if (l1==r1)
        return;
      build(u*2,l1,(l1+r1)/2);
      build(u*2+1,(l1+r1)/2+1,r1);
    }
    inline void jia(long long u,long long l1,long long r1,long long k)
    {
      if ((l[u]>r1)||(r[u]<l1)) return;
      if ((l[u]>=l1)&&(r[u]<=r1))
      {
        z[u]+=k*(r[u]-l[u]+1);
        return;
      }
      jia(u*2,l1,r1,k);
      jia(u*2+1,l1,r1,k);
      z[u]=z[u*2]+z[u*2+1];
    }
    inline long long qui(long long u,long long l1,long long r1)
    {
      if ((l1>r[u])||(r1<l[u])) return 0;
      if ((l1<=l[u])&&(r1>=r[u])) return z[u];
      return (qui(u*2,l1,r1)+qui(u*2+1,l1,r1));  
    }
    int main()
    {
        scanf("%lld",&n);
        for (i=1;i<=n;i++)
        {
            scanf("%lld",&c[i].z);
            c[i].q=i;
        }
        sort(c+1,c+n+1,cjj);
        build(1,1,n);
        cnt=0;
        for (i=1;i<=n;i++)
        {
            if (c[i].z>c[i-1].z) cnt++;//离散化
            d[c[i].q]=cnt;
        }
        for (i=n;i>=1;i--)
        {
            ans+=qui(1,1,d[i]-1);
            jia(1,d[i],d[i],1);
        }
        printf("%lld",ans);
        return 0;
    }

      3、求逆序对的应用

      逆序对的应用还是比较多的,比如康托展开等。

  • 相关阅读:
    李宏毅机器学习课程---1、机器学习介绍
    尚学python课程---15、python进阶语法
    尚学python课程---14、python中级语法
    尚学python课程---13、python基础语法
    Android4.2.2由于越来越多的物理按键(frameworks)
    ym——Android之ListView性能优化
    我学cocos2d-x (两) 采用Delegate(信托)
    mac提升yosemite后php 扩展修复
    JAVA学习课第五 — IO流程(九)文件分割器合成器
    第11周项目-2.2
  • 原文地址:https://www.cnblogs.com/szbszb/p/11637369.html
Copyright © 2011-2022 走看看