AGC032E Modulo Pairing


2020-02-10

给一个长度为 \(2n\) 的序列,要求将其两两匹配成 \(n\) 组,假设第 \(i\) 组为 \((x_i,y_i)\),求 \(\max_{i=1}^n(x_i+y_i)\bmod m\) 的最小值,\(1\le n\le 10^5,1\le m\le 10^9,0\le a_i<m\)

我们首先我们有:

\[ (x+y)\bmod m=\begin{cases} x+y&x+y\le m\\ x+y-m&x+y>m \end{cases} \]

接下来我们看几种情况:

按是否取模区分的四种区间配对调整情况

如果我们有 \(x_1\le x_2\le x_3\le x_4\),那么我们有这样 \(4\) 中情况:

第一种,\(x_3+x_4<m\),那显然 \((x_1,x_4),(x_2,x_3)\) 更优。

第二种,\(x_1+x_2\ge m\),和第一种一样。

第三种,\(\begin{cases}x_1+x_3<m\\x_2+x_4\ge m\end{cases}\),考虑到 \(x_2+x_4-m<x_2\),故有 \(\max\{x_1+x_3,x_2+x_4-m\}=x_1+x_3\),而考虑到 \(\begin{cases}x_1+x_2\le x_1+x_3\\x_3+x_4-m<x_3\end{cases}\),故有 \(\max\{x_1+x_3,x_2+x_4-m\}\ge \max\{x_1+x_2,x_3+x_4-m\}\)。所以 \((x_1,x_2),(x_3,x_4)\) 一定比 \((x_1,x_3),(x_2,x_4)\) 优。

我们再来看 \((x_1,x_4),(x_2,x_3)\) 的情况。如果有 \(\begin{cases}x_1+x_4\ge m\\x_2+x_3\ge m\end{cases}\),那就有 \(\begin{cases}x_1+x_4-m<x1\\x_2+x_3-m<x_2\end{cases}\),所以 \(\max\{x_1+x_4-m,x_2+x_3-m\}<x_2\le \max\{x_1+x_2,x_3+x_4-m\}\),此时 \((x_1,x_4),(x_2,x_3)\) 的方案更优。但是如果有 \(x_1+x_4\le m\) 或是 \(x_2+x_3\le m\),则答案将会更大。

第四种,\(\begin{cases}x_1+x_4<m\\x_2+x_3<m\\x_3+x_6\ge m\\x_4+x_5\ge m\end{cases}\)。根据前面的讨论,我们仅需比较 \((x_1,x_4),(x_2,x_3),(x_5,x_6)\)\((x_1,x_2),(x_3,x_4),(x_5,x_6)\) 即可,不难发现 \(\begin{cases}x_1+x_2\le x_1+x_4\\x_3+x_6-m<x_3\le x_2+x_3\\x_4+x_5-m\le x_5+x_6-m\end{cases}\),于是 \(\max\{x_1+x_2,x_3+x_6-m,x_4+x_5-m\}\le \max\{x_1+x_4,x_2+x_3,x_5+x_6-m\}\)

根据第一、二、三种情况,我们发现,最终的划分结果肯定是被分成两部分,左边部分最小的匹配,次大的和次小的匹配……右边也这样匹配。其中左边所有的匹配 \((x,y)\) 都有 \(x+y<m\),右边的匹配 \((x,y)\) 都有 \(x+y\ge m\)

根据第四种情况,我们可以发现蓝色的匹配数越多越好,于是我们考虑二分蓝色的匹配数量,最终确定答案。

代码可以看这里

cpp
#define _CRT_SECURE_NO_WARNINGS

#include <map>
#include <set>
#include <stack>
#include <ctime>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cctype>
#include <vector>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <fstream>
#include <iostream>
#include <algorithm>

using namespace std;

namespace pufanyi {

    inline char gc() {
        static const int L = 233333;
        static char sxd[L], *sss = sxd, *ttt = sxd;
        if (sss == ttt) {
            ttt = (sss = sxd) + fread(sxd, 1, L, stdin);
            if (sss == ttt) {
                return EOF;
            }
        }
        return *sss++;
    }

#ifndef _AT_HOME
#define dd c = gc()
#else
#define dd c = getchar()
#endif
    inline char readalpha() {
        char dd;
        for (; !isalpha(c); dd);
        return c;
    }

    inline char readchar() {
        char dd;
        for (; c == ' '; dd);
        return c;
    }

    template <class T>
    inline bool read(T& x) {
        bool flg = false;
        char dd;
        x = 0;
        for (; !isdigit(c); dd) {
            if (c == '-') {
                flg = true;
            } else if(c == EOF) {
                return false;
            }
        }
        for (; isdigit(c); dd) {
            x = (x << 1) + (x << 3) + (c ^ 48);
        }
        if (flg) {
            x = -x;
        }
        return true;
    }
#undef dd

    template <class T>
    inline void write(T x) {
        if (x < 0) {
            putchar('-');
            x = -x;
        }
        if (x < 10) {
            putchar(x | 48);
            return;
        }
        write(x / 10);
        putchar((x % 10) | 48);
    }

    template <class T>
    inline void writesp(T x) {
        write(x);
        putchar(' ');
    }

    template <class T>
    inline void writeln(T x) {
        write(x);
        puts("");
    }

    typedef long long LL;

    const int maxn = 200005;

    int n, m;
    int aa[maxn];

    inline bool check(int x) {
        int lim = x << 1;
        for (int l = lim + 1, r = n << 1; l < r; ++l, --r) {
            if (aa[l] + aa[r] < m) {
                return false;
            }
        }
        return true;
    }

    int Main() {
        read(n), read(m);
        for (int i = 1; i <= n << 1; ++i) {
            read(aa[i]);
        }
        sort(aa + 1, aa + (n << 1) + 1);
        int l = 0, r = n;
        while (l < r) {
            int mid = (l + r) >> 1;
            if (check(mid)) {
                r = mid;
            } else {
                l = mid + 1;
            }
        }
        int ans = 0;
        int lim = l << 1;
        for (int l = 1, r = lim; l < r; ++l, --r) {
            ans = max(ans, (aa[l] + aa[r]) % m);
        }
        for (int l = lim + 1, r = n << 1; l < r; ++l, --r) {
            ans = max(ans, (aa[l] + aa[r]) % m);
        }
        writeln(ans);
        return 0;
    }

}

int main() {
    return pufanyi::Main();
}

Cite this post

@misc{pu2020agc032e,
  author = {Pu, Fanyi},
  title  = {AGC032E Modulo Pairing},
  year   = {2020},
  month  = {2},
  url    = {https://pufanyi.com/blog/agc032-e}
}