题解 CF1729D
题目链接 CF1729D
题意
有长度为 n 的数组 $x$ 和 $y$ ,可以选择若干个下标,将选择的下标分成若干组(每组最少 2 个),使每组中下标对应的 $x$ 之和不大于 $y$ 之和。问最大的组数。
分析
因为每次都是选择对应的 $x_{i}$ 和 $y_{i}$,
那么不妨再写一个数组 $f_{i}$ , $f_{i} = y_{i} - x_{i}$ 。
对于成立的每一组, $f$ 之和大于 0 。
所以每一组必有一个 $f$ $> =0$ 。
结论 1 :长度都为 2。
证明:
对于长度大于 2 的每一组,一定可以将其中 $f<0$ 的全部不选,一定可以将其中多余的 $f>=0$ 的不选。
因此,对于最终组数最多情况,必然存在每一组长度都为 2 的情况。
结论2 : 每一组的 $f$ 要么是都 $>=0$ , 或者有一个 $<0$ 。
证明显然。
结论3 :对于每一个 $f >=0$ 的下标,能选择 $f<0$ 的就不让其选择 $f >= 0 $ 的。
因为要使组数最大,因此显然。
如此我们就有了代码的思路:
先对 $f$ 进行排序,并标记排序后第一个 $f>=0$ 的下标。
对于这个 $f$ ,
判断与我们现在没有选择的最大负值 $f$ 相加是否大于等于 0 ,
否则将其下一个 $f$ 与之组成一组。
AC 代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int n, m;
int a[N];
int T;
signed main() {
cin>>T;
while(T--) {
cin>>n;
for(int i=1; i<=n; ++i) {
cin>>a[i];
}
for(int j=1; j<=n; ++j) {
int x;
cin>>x;
a[j]=x-a[j];
}
sort(a+1,a+n+1);
int l=0;
for(int i=1; i<=n; ++i ) {
if(a[i]<0) l=i;
else break;
}
int cnt=0;
for(int i=l+1; i<=n; ++i) {
if(l!=0&&a[i]+a[l]>=0) cnt++,l--;
else {
++i;
if(i<=n)
cnt++;
}
}
cout<<cnt<<endl;;
}
return 0;
}

浙公网安备 33010602011771号