[NOIP2013 提高组] 火柴排队

题目链接

可以证明a中第k大应该对于b中第k大
满足此条件的两个数列,完成一次交换,有可能使得答案变劣

只对一个数列进行操作和对两个数列进行操作是等价的

数据很大,需要离散化
假设确定a数组,只移动b,你会发现很困难
这里不妨使得a数组的第一项为第一,第二项为第二……
对应的b数组中的数也进行替换

就会变成一个求逆序对的问题

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <map>
using namespace std;

#define MAXN 100005
#define MOD (100000000-3)

map <int,int> mpa,mpb;
int tota = 0,totb = 0;

int a[MAXN],b[MAXN],t[MAXN];
int index[MAXN];
int N;

struct Binary {
    #define lowbit(x) (x&(-x))

    int pre[MAXN];
    inline int query(int x) {
        int ans = 0;
        for(;x>0;x-=lowbit(x)) ans += pre[x];
        return ans;
    }
    inline void update(int x,int c) {
        for(;x<=N;x+=lowbit(x)) pre[x] += c;
    }
} tr;


int main() {

    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);

    cin >> N;
    
    for(int i=1;i<=N;++i) {
        cin >> a[i]; t[i] = a[i];
    }
    sort(t+1,t+1+N);
    mpa[t[1]] = ++tota;
    for(int i=2;i<=N;++i)
        if(t[i]!=t[i-1]) mpa[t[i]] = ++tota;
    for(int i=1;i<=N;++i) {
        a[i] = mpa[a[i]]; 
        if(index[a[i]]==0) index[a[i]] = i;
    }

    
    for(int i=1;i<=N;++i) {
        cin >> b[i]; t[i] = b[i];
    }
    sort(t+1,t+1+N);
    mpb[t[1]] = ++totb;
    for(int i=2;i<=N;++i)
        if(t[i]!=t[i-1]) mpb[t[i]] = ++totb;
    for(int i=1;i<=N;++i) {
        b[i] = mpb[b[i]]; b[i] = index[b[i]];
    }

    long long ans = 0;
    for(int i=1;i<=N;++i) {
        ans += tr.query(N) - tr.query(b[i]);
        ans %= MOD;
        tr.update(b[i],1);
    }

    cout << ans;

    return 0;
}
posted @ 2021-10-18 22:36  Neworld1111  阅读(36)  评论(0编辑  收藏  举报