基本思路:贪心,每次将 $A$ 中的数从大到小与 $B$ 中的数从小到大一一对应组合,即 $A$ 中最大的数与 $B$ 中最小的数组合, $A$ 中第二小的数与 $B$ 中第二大的数组和,其中最大的数对即为所求。
像这样:

非常简单易懂的贪心。
但是俗话说得好,贪心不难,但是难的是证明。
非常随意的证明:设数对 $(A_1,B_1)$ 是最大数对,下一个数对为 $(A_2,B_2)$ 。
根据我们之前的贪心思路,可知
$A_1
B_2$ 而要使最大数对的最大值减小,要么将 $A_1$ 与 $B$ 中更小的数组合,要么将 $B_1$ 与 $A$ 中更小的数组合,以前一种方法为例,新的两个数对为
$(A_2,B_1)$ 和 $(A_1,B_2)$
很容易发现
$A_2+B_1>A_1+B_1$
所以这样做反而会使最大值变得更大,后一种方法也一样,因此 $(A_1,B_1)$ 一定是所求的最大数对。
证毕。
在程序的具体实现中,由于 $1\leq A_i,B_i\leq 100$ ,还可以用桶排进行优化。
具体看代码:
#include<bits/stdc++.h>
using namespace std;
int n,a[105],b[105],c[105],d[105],x,y;
inline int read(){//快读
char ch=getchar();
int x=0,w=1;
while((ch>'9' || ch<'0') && ch!='-')ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(ch>='0' && ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*w;
}
int find(){
int i=1,j=100,maxx=0;
for(int k=1;k<=100;k++)//因为要对数组进行操作,所以用c,d数组进行代替。
c[k]=a[k],d[k]=b[k];
while(i<=100 and j>=1){
while(!c[i] and i<=100)
i++;
while(!d[j] and j>=1)
j--;
if(i>100 or j<1)
break;
maxx=max(i+j,maxx);//对最大值进行更新。
int w=min(c[i],d[j]);
d[j]-=w;c[i]-=w;
}
return maxx;
}
int main(){
n=read();
for(int i=1;i<=n;++i){
x=read();y=read();
a[x]++;b[y]++;
printf("%d\n",find());
}
}
- 然后就可以愉快地把这题水掉了。