ATG32E Modulo Pairing 笔记
原题链接:洛谷传送门
题意简述
给定
解决方案
不妨先考虑没有取模操作时的情况。显然我们先排个序,让最大的和最小的一对,次大的和次小的一对,依此类推,这样如括号嵌套的方案是最优的。也即
记
权值为 , 权值记为 。 首先,
一组, 一组显然不优。
接下来,一组(其权值记为 ), 一组(其权值记为 )显然也不优:
- 若
,则 ,不优。 - 若
,则 ,不优。 综上证毕。
啊但是现在加入了取模操作,怎么办呢?
首先我们发现,仍然有
不等式两边同增同减。显然。
这说明对于最终被取模的数对中的数,最优的方案也是如括号嵌套的。
接下来我们推导出:
显然有
。
又推导出
这告诉我们,需要取模的数对一定完全在不需要取模的对后面。因此,整体的匹配形成了这样一种形状:
也就是说,以某个下标
不过,这两部分的分界线怎么确定呢?实际上,这个分界线越靠左越好;也就是说我们要尽可能地从不减
半感性半理性地理解一下。左边的答案肯定不会更劣,因为删除一些元素不可能让这个集合通过加法规则组合出来的最大值变大;右边的答案也不会更劣,具体来说见下文:
显然我们肯定是尝试将数对里更大的元素拎出去,因为如果把更小的元素拎出去都行,那拎大的肯定更行且更有利于最小化答案。
这样,设我们调整之前的数对为
和 ,且 。那么调整之后的数对就是 和 。 现在我们需要证明
。 显然
。
又当且仅当 。此时 。
由此得证。
现在考虑代码实现。首先
代码
除排序之外
#include <bits/stdc++.h>
using namespace std;
const int MaxN=1e5+5;
int M,N,A[MaxN<<1];
void maxxer(int &x,int y){x=max(x,y);}
int main(){
scanf("%d%d",&N,&M);
for(int i = 1;i <= N*2;i++)scanf("%d",&A[i]);
sort(A+1,A+N*2+1);A[N*2+1]=M;int bkp=0;
for(int i=1,j=N*2+1;i<=N*2;i++){
while(A[j-1]+A[i]>=M)j--;
maxxer(bkp,i-(N*2-j));
}
if(bkp%2==0)bkp++;int ans=0;
for(int i=1,j=bkp-1;i<j;i++,j--)maxxer(ans,(A[i]+A[j])%M);
for(int i=bkp,j=N*2;i<j;i++,j--)maxxer(ans,(A[i]+A[j])%M);
printf("%d",ans);
return 0;
}
反思与总结
思考过程上,我们先从平常没有取模的情况开始思考起,然后推广到多出一个限制的情况,这是一种由平常到特别的思想。除此之外,本题关于序和最优性的大量结论还需要一定的推导能力。最后代码实现注意一些细节就行。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架