把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

题解 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;
}
posted @ 2022-11-22 22:14  djh0314  阅读(16)  评论(0)    收藏  举报  来源
浏览器标题切换
浏览器标题切换end