洛谷 P5749 [IOI2019]排列鞋子

题目链接

竟然是IOI的题目!我惊了!

结论,每只鞋子,找最近的去匹配,就是最优的

证明见木木 !的博客

我们于是有朴素算法

先将鞋子按照左右脚分类,再按值分类

然后从后往前依次配对所有鞋子

首先能配对的鞋子必定在它之前的,所以只用找对应的vector里的最后一只,然后坐标减一减就是贡献,注意左右脚的区别

然后标记两只鞋,表示已经用过,vector则弹出最后的元素(pop_back())

一提交 10pts???

原来有些鞋子匹配好了(由于我们从后往前,匹配好了就是移到最后形成一双),导致剩余鞋子之间的距离减小

我们开一个树状数组统计区间里有多少只鞋子已经不在了

每次计算贡献时减去区间内已经空了的位子数

[Code]

#include <bits/stdc++.h>
using namespace std;

int read(){
    int x=0,flag=1; char c;
    for(c=getchar();!isdigit(c);c=getchar()) if(c=='-') flag=-1;
    for(;isdigit(c);c=getchar()) x=((x+(x<<2))<<1)+(c^48);
    return x*flag;
}

const int N=1e5+10;

int n;
vector<int> a[N],b[N];
vector<int>::iterator it;
int g[N+N];
bool use[N+N];

int c[N+N];
int lowbit(int x) { return x&(-x); }
void update(int x,int y){
    for(int i=x;i<=n+n;i+=lowbit(i)) c[i]+=y;
}
int query(int x){
    int ret=0;
    for(int i=x;i>0;i-=lowbit(i)) ret+=c[i]; return ret;
}

int main() {
    n=read();
    for(int i=1;i<=n+n;i++){
        int x=read();
        g[i]=x;
        if(x>0) a[x].push_back(i);
        else b[-x].push_back(i);
    }
    
    long long ans=0;
    for(int i=n+n;i>=1;i--){
        if(use[i]) continue;
        if(g[i]>0){
            it=b[g[i]].end(); --it;
            ans+=i-*it-1-query(i)+query(*it-1);
            use[*it]=1;
            update(*it,1); update(i,1);
            b[g[i]].pop_back();
            a[g[i]].pop_back();
        }else{
            it=a[-g[i]].end(); --it;
            ans+=i-*it-query(i)+query(*it-1);
            use[*it]=1;
            update(*it,1); update(i,1);
            a[-g[i]].pop_back();
            b[-g[i]].pop_back();
        }
    }
    
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zzhzzh123/p/12219090.html