返回顶部

AtCoder Beginner Contest 181 E - Transformable Teacher (贪心,二分)

  • 题意:有一长度为奇数\(n\)的数组\(a\),和长度为\(m\)的数组\(b\),现要求从\(b\)中选择一个数放到\(a\)中,并将\(a\)分成\((n+1)/2\)个数对,求最小的所有数对差的和.

  • 题解:我们从\(b\)中选一个数出来,只和\(a\)中的一个元素配对,剩下的依然是\(a\)\(n-1\)个数两两配对,所以我们可以先求个前缀/后缀和,然后枚举\(b\)\(a\)中二分查找和\(b_i\)最近的数,但是会有个小问题,加入我们二分查找的位置是偶数,此时并不能完全配对,但是没关系,我们让偶数位置的前一个数与\(b_i\)配对,结果是一样的,比如\(a,b,c,d,e\),我们找与\(x\)最近的数,找到了\(b\),于是我们让\(b\)的前一个数\(a\)与其配对,有:\(a-x+b-c+d-e\),这个式子与\(b-x+a-c+d-e\)是等价的,所以这样就可以保证我们的贪心是对的(这个操作看了我半天),每次枚举维护一个最小值即可.

  • 代码:

    int n,m;
    int h[N],w[N];
    ll L[N],R[N];
    ll ans=1e18;
     
    int main() {
        ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
        cin>>n>>m;
        for(int i=1;i<=n;++i) cin>>h[i];
        for(int i=1;i<=m;++i) cin>>w[i];
     
        sort(h+1,h+1+n);
     
        for(int i=2;i<=n;i+=2) L[i]=L[i-2]+abs(h[i]-h[i-1]);
        for(int i=n-1;i>=1;i-=2) R[i]=R[i+2]+abs(h[i]-h[i+1]);
     
        for(int i=1;i<=m;++i){
            int pos=lower_bound(h+1,h+1+n,w[i])-h;
            if(pos%2==0) pos--;
            ans=min(ans,L[pos-1]+R[pos+1]+abs(h[pos]-w[i]));
        }
     
        cout<<ans<<endl;
     
        return 0;
    }
    
    
posted @ 2020-11-02 21:43  Rayotaku  阅读(211)  评论(0编辑  收藏  举报