題解/算法 {2576. 求出最多标记下标}

文章讨论了一种技巧性问题,通过排序数组后,利用双指针策略寻找最大匹配数。关键在于理解匹配的性质,如2*k<=n,以及匹配对的构造。算法包括二分查找枚举k和双指针方法,后者需注意指针移动规则,确保匹配的有效性。
摘要由CSDN通过智能技术生成

Link

Solution

这是一道技巧类的题;

如果用DP, 即便排了序, 比如当前数是9, 与他匹配的有4, 3, 2, 1 是很多的可能, 即便我们选择4, 那么 他的状态转移 即前面的状态 可以是8, 3 7, 3 … 也是很多的, 而且8 > 4, 因此不符合DP的线性递推;

@Delimiter

我们对数组 (长度 n n n) 进行排序, 本题的关键 是要知道: 假如有 k k k对匹配 (不一定是最大匹配), 它必然满足以下几个性质:
1 2 ∗ k ≤ n 2 * k \leq n 2kn;
2 假设开头最小的 k k k个元素是 a 1 , . . . , a k a_1, ..., a_k a1,...,ak, 末尾最大的 k k k个元素是 b 1 , . . . , b k b_1, ..., b_k b1,...,bk, 那么: 匹配 ( a 1 , b 1 ) , . . . , ( a i , b i ) (a_1, b_1), ..., (a_i, b_i) (a1,b1),...,(ai,bi) 一定是一个方案;

性质-2 非常非常重要, 它不一定是唯一方案, 但一定是一个合法方案;
比如: 1, 2, 3, 5, 6, 7, 我们让k = 2, 显然(1,6) (2,7)不是唯一方案 (但他是合法方案), 比如(2,5) (3,6)也是合法的;

你可以证明, 如果有k个匹配, 那么其一定可以通过转换 变成"性质-2"的形式;

因此, 性质-2 是本题的关键;

@Delimiter

算法1: 你可以使用"二分"来枚举这个k;

算法2: 可以使用双指针, 但这比较有难度, 它和"性质2"并不完全相同 有一些改动;
. 用一个l指针 来表示: [ 0 , . . . , l − 1 ] [0, ..., l-1] [0,...,l1]这些元素 一定可以匹配;
.r指针 并不就是指上面"性质-2"说的 (最大的k个元素的下标), 而是: 因为和 [ 0 , . . . , l − 1 ] [0, ..., l-1] [0,...,l1]这些元素 所匹配的 [ c , c + 1 , c + 2 , . . . , c c ] [c, c+1, c+2, ..., cc] [c,c+1,c+2,...,cc] (注意 c c cc cc并不一定是 n − 1 n-1 n1, 虽然按照上面的"性质-2", c c cc cc应该等于 n − 1 n-1 n1), 这些所匹配的元素 有个性质, 就是一定是递增的, 因此只要 [ . . . , l − 1 , l ] [..., l-1, l] [...,l1,l] 能和 [ . . . , r − 1 , r ] [..., r-1, r] [...,r1,r]能够匹配jik
. . 比如, 1 , 2 , 3 , 4 , 5 , 6 , 7 1, 2, 3, 4, 5, 6, 7 1,2,3,4,5,6,7, 对于 [ 1 , 2 ] [1, 2] [1,2]这两个元素, 我们可以选择其与 [ 3 , 4 ] [3,4] [3,4]匹配, 但这么做就错了, 因为, 根据"性质-1" 2 ∗ k ≤ n 2 * k \leq n 2kn, 任何一个匹配 都应该是: (一个属于 [ 0 , . . . , m i d ] [0,..., mid] [0,...,mid], 另一个属于 [ m i d + 1 , . . . , n − 1 ] [mid+1, ...,n-1] [mid+1,...,n1]), 因此, [ 1 , 2 ] [1,2] [1,2] 至少是应该和 [ 5 , 6 ] [5,6] [5,6]进行匹配;

故我们需要添加限制, 令 m i d = ( n + 1 ) / 2 mid = (n + 1)/2 mid=(n+1)/2, 则 l ∈ [ 0 , m i d ) , r ∈ [ m i d , n ) l \in [0, mid), r \in [mid, n) l[0,mid),r[mid,n), 即, 每个 r r r必然都是大于 l l l的;

而且, 我们最终得到的方案, 其实和"性质-2"不完全相同 (当然, 我们的根本 就是得到最大匹配k, 只要得到k就可以了)
比如, [1, 10, 11, 12], 我们第一次l = 1, r = 11是一个匹配, 然后就没有了, 因此, 如果从双指针算法看, 我们得到的匹配的是 ( 1 , 11 ) (1,11) (1,11), 而不是 ( 1 , 12 ) (1,12) (1,12), 但总之 能得到最大匹配就可以了;

Code

int maxNumOfMarkedIndices(vector<int>& A) {
    sort( A.begin(), A.end());
    //--
    int n = A.size();
    int r = (n + 1) / 2;
    int l;
    for( l = 0; l < (n + 1) / 2; ++l){
        while( r < n && A[l] * 2 > A[r]){
            ++ r;
        }
        if( r >= n){ return l * 2;}
        //--
        ++ r;
    }
    return l * 2;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值