1 条题解

  • 0
    @ 2026-5-6 18:34:45

    嗷嗷嗷校内模拟赛出了此题被细节搞死了。

    首先我们按 aa 从小到大排序,这样对于前 ii 个元素,aa 的最大值就是 aia_i
    以下记给第一位朋友买礼物的商店为集合 AA,给第二位朋友买礼物的商店为集合 BB。我们就钦定集合 AA 中,aa 的最大值就是 aia_i
    我们可以把所有 x(1xn)x(1 \le x \le n) 分成三组:

    1. ax<aia_x < a_i。这些 xx 可以属于集合 AA,也可以属于集合 BB,没有限制。
    2. ax=aia_x=a_i。这些 xx 同样既可以属于集合 AA,也可以属于集合 BB,但是至少要有一个属于集合 AA
    3. ax>aia_x>a_i。这些 xx 只能属于集合 BB

    现在我们的问题就变成了如何合理分配 axaia_x\le a_ixx 们,使得集合 BB 中的 bmaxb_{\max} 最接近 aia_i

    aa 相同的 ii 我们可以一起考虑,因此我们可以令当前的 ii 是满足 axaia_x \le a_i 的最大的 xx(也就是说,ai+1>aia_{i+1} > a_i)。
    这样第三组 xx 就变成了区间 [i+1,n][i+1,n]。这一段的 bb 是不可避免要计算的,因此可以先算出来。
    此时如果 bmaxb_{\max} 已经 ai\ge a_i 了,那么不用往下考虑了,因为已经无法令 bmaxb_{\max} 更接近 aia_i 了(最大值是单调递增的嘛)。
    否则就考虑在 [1,i][1,i] 中查找最接近 aia_ibxb_x。我们可以维护一个 set,set 中查前驱后继是很好的。
    但是要注意:

    • 如果 ax=aia_x=a_ixx 不止一个,那么直接找就行了。因为如果我们不幸找到了 bib_i,那么可以用别的 axa_x 来匹配 bib_i
    • 但是如果 ax=aia_x=a_ixx 只有一个,那么需要特判找到的 bb 是不是 bib_i。一个小方法是先在 set 中删掉 bib_i,再查前驱后继,查完再塞回去。
    • set 要开 multiset!!!

    ii11nn 扫一遍就结束了。

    以下代码带有一些校内模拟赛的注释。
    CF 的数据较为强悍,可以去 CF 交一发。
    【可以扩展思考:如果要求最大值怎么做?】

    #include<set>
    #include<queue>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    pair<int,int>s[500005];
    priority_queue<pair<int,int>>heap;
    int n,as1=1e9+5,as2;multiset<int>fnd;
    void sol_as1()
    {
        for(int i=1;i<=n;i++) heap.push({s[i].second,s[i].first});
        //按b从大到小排序
        for(int i=1;i<=n;i++)
        {
            int cnt=0,a=s[i].first;
            while(i!=n&&a==s[i+1].first)
            fnd.insert(s[i].second),i++,cnt++;
            fnd.insert(s[i].second),cnt++;
            while((!heap.empty())&&heap.
            top().second<=a) heap.pop();
            if(!heap.empty())
            {
                int bmx=heap.top().first;if(bmx>=a)
                {as1=min(as1,bmx-a);continue;}
                as1=min(as1,a-bmx);
            }
            if(cnt>1)
            {
                auto x=fnd.lower_bound(a);
                if(x!=fnd.end()) as1=min(as1,(*x)-a);//>=x中取最小
                //——等一下它不会没超过bmx吧?但如果如此那么fnd<=bmx<=a,显然不会统计。
                if(x!=fnd.begin()) x=prev(x),as1=min(as1,a-(*x));continue;
            }/*auto x=fnd.lower_bound(a+1);
            //如果a只有一个,那么fnd中有且仅有一个a,只要取到比它大就好。
            // if(x!=fnd.end()&&((*x).second!=s[i].first
            // ||(*x).first!=s[i].second)) as1=min(as1,(*x)-a);
            x=fnd.lower_bound(a);if(x==fnd.begin()) continue;
            x=prev(x),as1=min(as1,a-(*x));*/
            fnd.erase(fnd.find(s[i].second));
            auto x=fnd.lower_bound(a);
            if(x!=fnd.end()) as1=min(as1,(*x)-a);
            if(x!=fnd.begin()) x=prev(x),as1=min(as1,a-(*x));
            fnd.insert(s[i].second);
        }
    }
    int main()
    {
        // freopen("manyhacks.in","r",stdin);
        // freopen("manyhacks.out","w",stdout);
        scanf("%d",&n);for(int i=1;i<=n;i++)
        scanf("%d%d",&s[i].first,&s[i].second);
        sort(s+1,s+n+1);sol_as1();
        printf("%d",as1);
    }//注意大样例很水。虽然自己生成的数据疑似可能也很水。
    //注意捆绑测试。
    
    • 1

    信息

    ID
    11054
    时间
    1000ms
    内存
    512MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者