Match Points CodeForces 1156C 二分答案

CodeForces 1156C Match Points

传送门:https://codeforces.com/problemset/problem/1156/C

You are given a set of points x 1 , x 2 , . . . , x n x_1, x_2, ..., x_n x1,x2,...,xn on the number line.
Two points i i i and j j j can be matched with each other if the following conditions hold:
neither i nor j is matched with any other point;
∣ x i − x j ∣ ≥ z |x_i−x_j|≥z xixjz.What is the maximum number of pairs of points you can match with each other?

Input
The first line contains two integers n n n and z ( 2 ≤ n ≤ 2 ⋅ 1 0 5 , 1 ≤ z ≤ 1 0 9 ) z (2≤n≤2⋅10^5, 1≤z≤10^9) z(2n2105,1z109) — the number of points and the constraint on the distance between matched points, respectively.
The second line contains n n n integers x 1 , x 2 , . . . , x n ( 1 ≤ x i ≤ 1 0 9 ) x_1, x_2, ..., x_n (1≤x_i≤10^9) x1,x2,...,xn(1xi109).

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

题意:
给出一个数组 a a a和一个数 z z z,问在 a a a中最多可以选择出多少对 i i i j j j,满足 ∣ x i − x j ∣ ≥ z |x_i−x_j|≥z xixjz i i i j j j不能重复选择。

思路:
假设 x x x是猜测的最多的对数, s s s是真实的最多的对数,那么对于所有可行的 x x x,都有 x < = s x<=s x<=s
f ( x ) = ( x < = s ? 1 : 0 ) f(x)=(x<=s?1:0) f(x)=(x<=s?1:0)具有单调性,所以可以二分找答案。
先将数组 a a a排序,然后二分答案搜索最大的 x x x, x x x表示最多可以选择出多少对 i , j i,j i,j。在check函数中,我们可以在排好序的 a a a里挑选出最小的 x x x个数,也就是前 x x x个,为它们匹配最大的 x x x个数字一一配对,可以证明这是最优的情况,也就是能够匹配出最多对的情况。然后我们一一检查,如果出现了 a [ j ] − a [ i ] < z a[j]-a[i]<z a[j]a[i]<z,那么这个 a [ i ] a[i] a[i]就需要更大的 a [ j ] a[j] a[j],但如果给这个 a [ i ] a[i] a[i]匹配更大的 a [ j ] a[j] a[j],当前的 a [ j ] a[j] a[j]就会被浪费了,从而凑不出完整的 x x x对,所以此时return 0 , 这个 x x x不成立。

代码:

#include<iostream>
#include<algorithm>
using namespace std ;
#define ll long long
const ll N = 2e5+9 ;
void updata( ll &a , ll b ){if(b>a)a=b;}
ll n , z ;
ll a[ N ] ;
bool check( ll x ){
    if( x > n/2 ) return 0 ;
    for( int i = 1 ; i <= x ; i ++ ){
        ll p1 = i , p2 = n-x+i ;//第i个和倒数第i个作比较
        if( a[ p2 ] - a[ p1 ] < z ) return 0 ;
    }
    return 1 ;
}
int main(){
    cin >> n >> z ;
    for( int i = 1 ; i <= n ; i ++ ) cin >> a[ i ] ;
    sort( a+1 , a+1+n ) ;
    ll l , r , mid , ans = -1 , f ;
    l = 0 , r = n+9 ;
    while( l <= r ){
        mid = l+r >> 1 ;
        f = check( mid ) ;
        //cout << "mid=" << mid << " f=" << f << "\n" ;
        if( f ){ l = mid + 1 ; updata( ans , mid ) ; }
        else r = mid - 1 ;
    }
    cout << ans << "\n" ;
return 0 ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值