题意

原题
给出\(2n\)\(\leq m\)的数,求最优的两两配对方案
使\(n\)\((x,y)\)\((x+y)mod \space m\)最大值最小
\(n\leq 10^5,m \leq 10^9\)

思路

排序后大胆猜测
发现结论是: 一定存在一种最优解,使得以某个位置为界,两边分别首尾匹配,且满足左边的每一对的和都\(<m\), 右边每一对的和都\(≥m\).
证明可以看题解,大概因为每一种别的形式的解都可以转化到它,一定的等价或更优的
这样子我们就容易得到\(O(n^2)\)的枚举+判断的写法

接着发现:

  • 界线越左,左边的每一对越容易变成第一类(数都变小了)。
  • 界线越左,右侧的每一对越难变第二类。
  • 在满足条件情况下,界线越左,最大值就越小。
  • 如果左边不满足,右边一定是满足(因为右边的数都比左边大加起来任然\(<m\),右边一定全部\(<m\)

也就是界线是可以二分的,所以就做完了

#include <bits/stdc++.h>
using std::max;
using std::min;
int n,m,a[200005],ans=0,Ans;
int main(){
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n*2;i++)
        scanf("%d",&a[i]);
    std::sort(a+1,a+2*n+1);
    int l=0,r=n;
    while (l<=r){
        int mid=(l+r)>>1;
        bool f=true;
        int t=mid<<1;
        int ans=0;
        if (f) for(int i=t+1,j=2*n;i<j;i++,j--)
            if (a[i]+a[j]<m){
                f=false;break;
            }
        if (f){
            Ans=mid;
            r=mid-1;
        }else l=mid+1;
    }
    int t=Ans*2;
    for (int i=1;i<=Ans;i++) ans=max(ans,a[i]+a[t-i+1]);
    for(int i=t+1,j=2*n;i<j;i++,j--) ans=max(ans,a[i]+a[j]-m);
    printf("%d\n",ans);
} 

后记

连二分都能写错的我。。。

02-10 02:26