码迷,mamicode.com
首页 > 其他好文 > 详细

精灵魔法

时间:2020-07-06 13:06:46      阅读:128      评论:0      收藏:0      [点我收藏+]

标签:std   class   inf   void   lower   操作   分析   put   long   

精灵魔法(逆序对 \(\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\n",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\n",ans);
}
int main(){
    Solve();
    return 0;
}

精灵魔法

标签:std   class   inf   void   lower   操作   分析   put   long   

原文地址:https://www.cnblogs.com/hbhszxyb/p/13253975.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!