[分讨] [AGC032E] Modulo Pairing

posted on 2024-06-12 05:34:38 | under | source

\((a,b)\) 表示 \((a+b)\bmod m\)

首先让 \(a_i\) 从小到大排,假如没有取模就是让第 \(i\) 大和第 \(i\) 小这样搭配。

那么加上取模,因为 \(\forall a_i <m\),所以有个小性质:\(a_i+a_j-m< a_i,a_j\)

回顾一开始的贪心策略我们是怎么证明的,是对 \(a\le b\le c\le d\) 进行讨论,本题也可以这样试试:

经过尝试发现,\((a,c),(b,d)\) 是无论如何都不优的。

证明:

  • \(a+c\ge m\):数对同时减 \(m\) 直接比较就好,那么 \((a,d)\le (b,d)\)\((b,c)\le (a,c)\),调整后不劣。

  • 反之,若 \(b+d<m\):同上,\((a,c),(b,d),(a,d),(b,c)<m\),所以调整后不劣。

  • 反之:则 \((b,d)<b\le a+c=(a,c)\),那么其最值被 \((a,c)=a+c\) 取到。同理,对于方案 \((a,b),(c,d)\),其最值被 \((a,b)=a+b\) 取到。显然 \((a,b)\le (a,c)\),所以调整后不劣。

综上,所有数对只能有包含关系,不能交叉。

(蒟蒻做到这就不会推了 qwq。)

然后发现,\(\max((a,d),(b,c))\le \max((a,b),(c,d))\) 在绝大多数情况下都满足。具体而言,只要所有数对同时 \(<m\)\(\ge m\) 即可(即同时减去一个值)。

对其余情况(减去的数不同)讨论:

\(a+d\ge m,b+c<m\),那么 \(\max((a,d),(b,c))=b+c\)\(\max((a,b),(c,d))=a+b\),拆开更优。另一种情况同理。

结合以上讨论,若存在两个数对减去的数不一样,那么它们不可能包含;若相等,则必然包含。

于是,必然存在一种最优划分可以找到一个分界点,拆分为两区间,满足左边数对都 \(<m\),右边都 \(\ge m\),且同一区间内都是最大最小两两相配的。

暴力枚举是平方的,怎么优化?放开限制,允许 \((a,b)\) 只在 \(a+b\ge m\) 时减去 \(m\)。令右边都减去 \(m\),容易发现,右边越大越优,但是太大了就会非法。

二分计算即可,复杂度 \(O(n\log n)\)

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

#define pir pair<int, int>
const int N = 2e5 + 5, inf = 2e9 + 5;
int n, mod, a[N];

inline pir calc(int l, int r){
	pir p = {inf, 0}; //max初值不要设成-2e9,后面又减了1e9会爆int 
	for(int i = l, j = r; i < j; ++i, --j) 
		p.first = min(p.first, a[i] + a[j]), p.second = max(p.second, a[i] + a[j]);
	return p;
}
signed main(){
	cin >> n >> mod;
	for(int i = 1; i <= n << 1; ++i) scanf("%d", &a[i]);
	sort(a + 1, a + 1 + (n << 1));
	int l = 0, r = n + 1, mid;
	while(l + 1 < r){
		mid = (l + r) >> 1;
		if(calc(2 * mid - 1, n << 1).first >= mod) r = mid;
		else l = mid; 
	}	
	r = 2 * r - 1;
	cout << max(calc(1, r - 1).second, calc(r, n << 1).second - mod);
	return 0;
}
posted @ 2026-01-12 20:13  Zwi  阅读(1)  评论(0)    收藏  举报