zoukankan      html  css  js  c++  java
  • luogu P1908 逆序对

    emmm

    想写一下逆序对

    用了两种方法

    归并排序和树状数组

    我们看到这道题正常的思路就是暴力(也有可能仅限于本蒟蒻这么想

    然后写出了这样的代码

    #include<cstdio>
    using namespace std;
    int a[500010];
    int main() {
        int n,ans = 0;
        scanf("%d",&n);
        for(int i = 1; i <= n; i++) {
            scanf("%d",&a[i]);
        }
        for(int i = 1; i <= n; i++)
            for(int j = i + 1; j <= n; j++)
                if(a[j] < a[i])
                    ans++;
        printf("%d",ans);
        return 0;
    }

    emmm

    十分简洁的t了十五个点拿了25分

    其实暴力就够了嘛。

    但是仔细想逆序对其实就是排序的过程,暴力的思路就是冒泡,显然超时

    那么还有一种排序叫做归并

    复杂度。。。(我不知道请您自己百度orz 

    emmmm

    归并排序的思路大概都懂吧。

    上代码

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define maxn 500010
    #define ll long long
    
    ll a[maxn],n;
    ll qwq[maxn];
    ll ans;
    
    void qsort(ll l,ll r){
      if(l == r)
        return ;
      ll mid = (l + r) >> 1;
      qsort(l,mid);
      qsort(mid + 1,r);
      ll i = l,j = mid + 1,k = l;
      while(i <= mid && j <= r){//合并操作
        if(a[i] <= a[j])
          qwq[k++] = a[i++];
        else
          qwq[k++] = a[j++],ans += mid - i + 1;
      }
      while(i <= mid)
        qwq[k] = a[i],k++,i++;
      while(j <= r)
        qwq[k] = a[j],k++,j++;
      for(ll i = l;i <= r;i++)
        a[i] = qwq[i];
    }//其实归并排序不是很难emmmm多想一想就好啦
    
    int main(){
      scanf("%lld",&n);
      for(ll i = 1;i <= n;i++)
        scanf("%lld",&a[i]);
      qsort(1,n);
      printf("%lld",ans);
      return 0;
    }

    再然后呢

    学长给我讲了树状数组求逆序对

    这里我们再来膜一下 tql!!!%%%

    emmmm

    大概就是

    利用桶排序的思路,从后往前将数放入数组里

    在每一次的数组处加一,并求出其之前的前缀和

    最后将前缀和加和,就是答案啦

    手推一下就会了~

    (当然前置知识树状数组不用我说吧。。。

    然后我正在和离散化过程中两个数相同的情况作斗争,目前写的只有40分

    啊对

    离散化

    就是如果有三个数

    30000000 40000000 10000000

    太大了

    这时候我们可以把这三个数简化成

    2 3 1

    emmmm

    大概这就叫离散化吧

    先放一下40分代码

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define maxn 500010
    #define ll long long
    
    ll ans,n;
    ll www[maxn];
    
    struct Tree{
      ll num,QAQ,qwq;
    }tree[maxn];
    
    bool cmp(Tree x,Tree y){
      return x.QAQ < y.QAQ;
    }
    
    bool ccmp(Tree x,Tree y){
      return x.qwq < y.qwq;
    }
    
    ll lowbit(ll x){
      return x & (-x);
    }
    
    void add(ll x){
      while(x <= n){
        www[x] ++;
        x += lowbit(x);
      }
    }
    
    ll sum(ll x){
      ll orz = 0;
      while(x > 0){
        orz += www[x];
        x -= lowbit(x);
      }
      return orz;
    }
    
    int main(){
      scanf("%lld",&n);
      for(ll i = 1;i <= n;i++){
        scanf("%lld",&tree[i].QAQ);
        tree[i].qwq = i;
      }
      sort(tree + 1,tree + n + 1,cmp);
      for(ll i = 1;i <= n;i++)
        tree[i].num = i;
      sort(tree + 1,tree + n + 1,ccmp);
      for(ll i = n;i >= 1;i--){
        add(tree[i].num);
        ans += sum(tree[i].num - 1);
      }
      printf("%lld",ans);
      return 0;
    }

    等我什么时候用树状数组拿了100

    再来写详细注释orz

    【溜

    -------------------------------------------------------第二天的分割线------------------------------------------------------------------

    emmmm

    写出来了诶

    然而还是不想写注释

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define maxn 500010
    #define ll long long
    
    ll ans,n;
    ll www[maxn];
    
    struct Tree {
        ll num,QAQ,qwq;
    } tree[maxn];
    
    bool cmp(Tree x,Tree y) {
        return x.QAQ < y.QAQ;
    }
    
    bool ccmp(Tree x,Tree y) {
        return x.qwq < y.qwq;
    }
    
    ll lowbit(ll x) {
        return x & (-x);
    }
    
    void add(ll x) {
        while(x <= n) {
            www[x] ++;
            x += lowbit(x);
        }
    }
    
    ll sum(ll x) {
        ll orz = 0;
        while(x > 0) {
            orz += www[x];
            x -= lowbit(x);
        }
        return orz;
    }//以上,树状数组操作
    
    int main() {
        scanf("%lld",&n);
        for(ll i = 1; i <= n; i++) {
            scanf("%lld",&tree[i].QAQ);//QAQ记录原始数据
            tree[i].qwq = i;//qwq记录输入顺序
        }
        sort(tree + 1,tree + n + 1,cmp);//排QAQ来进行我那被学长称为独特的离散化操作
    // for(ll i = 1;i <= n;i++)
        // tree[i].num = i;
        int now = 1;
        int last = tree[1].QAQ;
        tree[1].num = 1;
        for(int i = 1; i <= n; i++) {
            if(tree[i] .QAQ == last) {
                tree[i].num = now;
                continue;
            }
            last = tree[i].QAQ;
            now++;
            tree[i].num = now;
        }//这里就是我从40到100的转折点emmmm防止数据重复
        sort(tree + 1,tree + n + 1,ccmp);//排序qwq使恢复正常输入顺序
        for(ll i = n; i >= 1; i--) {
            add(tree[i].num);
            ans += sum(tree[i].num - 1);
        }//从后往前依次放到树状数组里然后求和
        printf("%lld",ans);
        return 0;
    }

    emmmm

    写出来了开心~

    -----------------------------------------再次分割线----------------------------------------------------

    突然想起来把两种代码运行结果放一起比较一下

    首先这是归并排序的emmmm

     然后是树状数组的 

    emmmmm没有对比就没有伤害啊

  • 相关阅读:
    Android常用的图片加载库
    BottomBar之Android底部菜单
    弧形菜单(Android)
    购物车动画(Android)
    基于zxing的二维码(网格)扫描
    Android菜单(动画菜单、360波纹菜单)
    Retrofit实现图文上传至服务器
    PAT甲级 1010 Radix 详细题解
    Leetcode刷题第三期Week1——模拟
    Matlab数据标准化——mapstd、mapminmax
  • 原文地址:https://www.cnblogs.com/sevenyuanluo/p/10127754.html
Copyright © 2011-2022 走看看