zoukankan      html  css  js  c++  java
  • Codeforces C Match Points(二分贪心)

    题目描述:

    Match Points

    time limit per test

    2 seconds

    memory limit per test

    256 mega bytes

    input

    standard input

    output

    standard output

    You are given a set of points x1, , ..., x**n

    Two points iand jcan be matched with each other if the following conditions hold:

    • neither i nor j is matched with any other point;
    • |x**ix**j|≥z.

    What is the maximum number of pairs of points you can match with each other?

    Input

    The first line contains two integers n

    and (2≤n≤2⋅105) — the number of points and the constraint on the distance between matched points, respectively.

    The second line contains n integers , x2 (1≤x**i≤109

    Output

    Print one integer — the maximum number of pairs of points you can match with each other.

    Examples

    Input

    Copy

    4 2
    1 3 3 7
    

    Output

    Copy

    2
    

    Input

    Copy

    5 5
    10 9 5 8 7
    

    Output

    Copy

    1
    

    Note

    In the first example, you may match point 1

    with point (|3−1|≥2 with point 4).

    In the second example, you may match point 1

    with point (|5−10|≥5)

    思路:

    刚开始就想的是匹配嘛,一看到匹配想到二分图最大匹配,嗯~匈牙利算法,建个图,跑一下试试。不过看样子数据范围有点大,有超时的可能(必然)。不管了,想到这个先写写吧。怎么建图呢?把满足条件的两个点之间连一条边,等等,好像有重复啊,我一个数匹配了就不能再用了啊。我自以为可以解决问题的做法:对一个数来说枚举从他的下一个到末尾。是不是就可以了呢?

    不是。我真的是,刚学了二分图就想什么都往上面套,明明怎么建图都还没学过,这样还是不可能建出正确的图。因为一个顶点被用了之后是不知道知道它已经被用了的,这就建不出二分图。

    天真的我以为模板写错了,又用了最大流来了好几遍,一直WA,真好。

    我就想到二分,然后有一种直觉告诉我,我把数组排个序,然后用lower_bound给每个数来一下查找满足条件的最小元素。但也是直觉产生怀疑,为什么,这样贪心正确吗?有没有可能这里lower_bound了配对以后就影响了后面元素的配对,而且是连环影响,本来可以产生更多配对,结果由于贪心配对数变少了。怀疑是正确的,比如一组例子:

    4 2

    1 3 4 5

    如果找这种方法只能配出1,3一对来,实际上是两对:1,4和3,5

    然后我想,那我统计一下元素可能配对的次数,从可能配对次数最小的开始配对,因为它们最不容易配对,优先满足它们可能会让总数大一些,于是又用了结构体排序什么的,也不正确。

    眼看着我里正确的思路越来越远,也越来越想不到正确的解。知道是二分复杂度才能下去,知道是贪心才能得出正确解,但我的思路好像很奇怪?

    现在来看看正确的思路,我们想最优的情况是什么?是每个元素都配了对,一共n/2对,是不是?那么这个时候配对情况是怎样的呢?是不是前一半小的配后一半大的?如果这点想到了,离正确二分就不远了。就是二分这个排序好的数组,用后一半跟前一半的元素配对,具体的,设中间为mid,最后一个从mid-1开始往前面配对,一旦出现配对元素,答案统计,并更新下一次配对开始的起点为当前位置的前一个位置。(为什么?因为当前如果配好了对,由于数组已经排好了序,下一次是比这次参加配对的后半段的元素更小的一个元素,这个位置及以后的位置上的元素明显不可能满足差值大于z的条件)。

    代码:

    #include <iostream>
    #include <algorithm>
    #define max_n 200005
    using namespace std;
    int n;
    int z;
    int a[max_n];
    int ans = 0;
    int main()
    {
        cin >> n >> z;
        for(int i = 0;i<n;i++)
        {
            cin >> a[i];
        }
        sort(a,a+n);
        int mid=n/2;
        int l = mid-1;
        for(int i = n-1;i>=mid;i--)
        {
            while(l>=0)
            {
                if(abs(a[l]-a[i])>=z)
                {
                    ans++;
                    l--;
                    break;
                }
                l--;
    
            }
        }
        cout << ans << endl;
        return 0;
    }
    

    后记:

    学习模板固然有一定的作用,可是如果在学习过程中产生了依赖,什么都想套用模板而不去思考,后果是什么?什么题都想先百度题解,不认真思考的后果是什么?orz

    我虽然菜,而且菜啊

  • 相关阅读:
    K3s+Jetson Nano,在边缘端实现实时视频分析!
    15分钟连接Jetson Nano与K8S,轻松搭建机器学习集群
    配置高可用K3s集群完全攻略
    K3s+Sysdig,8分钟部署并保护集群安全!
    1款工具助力Rancher HA快速部署,极速提升研发测试效率
    连刷40道题,告别动态规划,谈谈我的经验
    直通BAT算法精讲视频教程分享
    关于三次握手和四次挥手,面试官想听到怎样的回答?
    Redisson 分布式锁实战与 watch dog 机制解读
    Spring 注解动态数据源设计实践
  • 原文地址:https://www.cnblogs.com/zhanhonhao/p/11332901.html
Copyright © 2011-2022 走看看