• 精灵魔法


    精灵魔法(逆序对 (circ ))

    • (Tristan) 解决了英灵殿的守卫安排后,便到达了静谧的精灵领地——(Alfheim)。由于(Midgard) 处在 (Alfheim) 和冥界 (Hel) 的中间,精灵族领地尚未受到冥界恶灵的侵入。族长 (Galanodel) 为了帮助米德加尔特抵御外敌,对邪恶亡灵军团使用了高等魔法,从而使得亡灵军团每个士兵的行进速度变得不一致,从而打乱冥王 (Hel) 安排的最佳阵型。
    • 由于这个军团离 (Midgard) 还很远,因此在抵达 (Midgard) 之前,对于(A,B) 两个亡灵,若 (A) 的初始位置在 (B) 后面且 (A) 的速度比 (B) 快,(A) 就会冲到 (B) 的前面去。现在 (Galanodel) 想知道,会有多少对亡灵之间出现反超现象?

    Input

    • 第一行一个整数 (n),表示排成一队的邪恶亡灵军团有多少人。
    • 第二行 (n) 个整数 (a[i]),表示邪恶亡灵们在数轴上的初始坐标。数据保证这些坐标全部不同。亡灵军团向数轴正方向前进。
    • 第三行 (n) 个整数 (v[i]),表示邪恶亡灵们的行进速度。

    Output

    • 一行一个正整数 (k),表示「反超」的个数。

    Sample Input

    3
    1 2 3
    2 1 3
    

    Sample Output

    1
    

    Hint

    • 对于 (30\%) 的数据,(1<= N<= 1000)
    • 对于(100\%) 的数据,(1<=N<= 10^5)
    • 所有数据的绝对值均不超过 (maxlongint)
    • 来源:(cogs1144)

    分析

    • 经典的求逆序对有归并排序和树状数组,树状数组需要先离散化。

    归并排序Code

    #include <bits/stdc++.h>
    const int maxn=1e5+5,Inf=2147483647;
    typedef long long LL;
    struct Node{
        LL pos,v;
        bool operator <(const Node &a)const{
            return pos<a.pos;
        }
    }e[maxn];
    LL a[maxn],b[maxn],ans=0;
    int n;
    void Read(){
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
          scanf("%lld",&e[i].pos);
        for(int i=1;i<=n;++i)
          scanf("%lld",&e[i].v);
        std::sort(e+1,e+n+1);
        for(int i=1;i<=n;++i)
          a[i]=e[i].v;
    }
    void Print(){
        for(int i=1;i<=n;++i)
            printf("%lld ",a[i]);
    }
    void Merge(int l,int mid,int r){//合并操作
        int i=l,j=mid+1,k=0;//i指向前面区间第一个元素,j指向后面区间第一元素
        while(i<=mid && j<=r){//取两个序列前面的较小者
            if(a[i]<=a[j])b[++k]=a[i++];
            else{
                ans+=mid-i+1;//a[i]~a[mid]均能和a[j]组成逆序对
                b[++k]=a[j++];
            } 
        }//跳出循环两个序列中有一个为空
        while(i<=mid)//若比较完之后,第一个有序区仍有剩余
            b[++k]=a[i++];
        while(j<=r)//若比较完之后,第二个有序区仍有剩余
            b[++k]=a[j++];
        for(i=l,k=1;i<=r;++i,++k)//把合并后的排好序的序列拷贝到数组a[l,r]
            a[i]=b[k];
    }
    void Merge_sort(int l,int r){
        if(l<r){//把区间分成两部分
            int mid=l+(r-l)/2;
            Merge_sort(l,mid);//递归左区间
            Merge_sort(mid+1,r);//递归右区间
            Merge(l,mid,r);//合并左右两区间
        }
    }
    void Solve(){
        Read();
        Merge_sort(1,n);
        printf("%lld
    ",ans);
    }
    int main(){
        Solve();
        return 0;
    }
    

    树状数组Code

    #include <bits/stdc++.h>
    typedef long long LL;
    const LL maxn=1e5+5;
    struct Node{
        LL pos,v;
        bool operator <(const Node &a)const{
            return pos<a.pos;
        }
    }a[maxn];
    LL b[maxn],c[maxn];
    LL n;
    LL lowbit(LL x){
        return x & -x;
    }
    void Updata(LL x){
        for(LL i=x;i<=n;i+=lowbit(i))
            c[i]++;
    }
    LL Query(LL x){
        LL ans=0;
        for(LL i=x;i;i-=lowbit(i)){
            ans+=c[i];
        }
        return ans;
    }
    void Solve(){
        scanf("%lld",&n);
        for(int i=1;i<=n;++i)
            scanf("%lld",&a[i].pos);
        for(int i=1;i<=n;++i){
            scanf("%lld",&a[i].v);
            b[i]=a[i].v;
        }
        std::sort(a+1,a+n+1);
        std::sort(b+1,b+n+1); 
        for(int i=1;i<=n;++i)
            a[i].v=std::lower_bound(b+1,b+n+1,a[i].v)-b;
           
        LL ans=0;
        for(int i=n;i>=1;--i){
            ans+=Query(a[i].v-1);
            Updata(a[i].v);
        }
        printf("%lld
    ",ans);
    }
    int main(){
        Solve();
        return 0;
    }
    
  • 相关阅读:
    加载web项目时报的错误:Tomcat version 6.0 only supports J2EE 1.2, 1.3, 1.4, and Java EE 5 Web modul
    js修改title
    14.Android UiAutomator 图像处理
    13.UiAutomator 辅助APK的使用
    12.UiAutomator 获取系统信息
    11.UiAutomator 相关JAVA知识
    10.Android UiAutomator Junit 断言函数的使用
    面向对象基本关键词的解释
    Java图形界面——Border
    java文本编辑器v2.0 图形用户界面
  • 原文地址:https://www.cnblogs.com/hbhszxyb/p/13253975.html
Copyright © 2020-2023  润新知