zoukankan      html  css  js  c++  java
  • 洛谷P5682 次大值 题解

    题目链接:https://www.luogu.com.cn/problem/P5682

    题目描述

    Alice 有 (n) 个正整数,数字从 (1 sim n) 编号,分别为 (a_1,a_2, cdots , a_n)
    Bob 刚学习取模运算,于是便拿这 (n) 个数进行练习,他写下了所有

    (a_i) mod (a_j (1 le i,j le n wedge i eq j))

    的值,其中 mod 表示取模运算。

    Alice 想知道所有的结果中,严格次大值是多少。将取模后得到的所有值进行去重,即相同的结果数值只保留一个,剩余数中第二大的值就称为严格次大值。

    解题思路

    首先我们要排除无关因素带来的影响。

    这里很明显的一个无关因素就是重复的元素。

    我们假设存在 (a_i = a_j)(i eq j),则对于任何一个 (k eq i wedge k eq j)

    • (a[i]) mod (a[k] = a[j]) mod (a[k])
    • (a[k]) mod (a[i] = a[k]) mod (a[j])

    所以数值相同的两个元素是等价的。

    我们可以给 (a1)(a_n) 从小到大排序并去重。

    我们假设去重后还剩下 (m) 个元素,且这些元素满足 (a_1 lt a_2 cdots lt a_m)

    则我们可以分 (m=1)(m=2)(m gt 2) 三种情况分开讨论:

    m = 1

    (m=1) 时,数组中只有一个元素:

    • 如果 (n = 1),则不存在答案,输出 (-1)
    • 如果 (n gt 1),则说明数组中所有的元素都是相同的,则任意 (a_i) mod (a_j) 的结果都是 (0),所以只存在一个最大值 (0),不存在次大值,同样也输出 (-1)

    m = 2

    (m=2) 时,只有两个候选答案 (a_1) mod (a_2)(a_2) mod (a_1),又因为 (a_1) mod (a_2 = a_1)(a_2) mod (a_1 lt a_1)(余数必然小于除数),所以次大值肯定是 (a_2) mod (a_1)

    m > 2

    (m gt 2) 时,可以确定的是最大值是 (a_{m-1}) mod (a_m)

    次大值应该是以下两者的较大值:

    • (a_{m-2}) mod (a_m)
    • (a_{m}) mod (a_{m-1})

    详细证明

    为了方便讲述起见,我接下来用 (a \% b) 来表示 (a) mod (b),并且我们这里只证明 (m gt 2) 的情况。

    这里有一个非常重要的基础性质:

    性质1:余数永远小于除数!

    我们接下来会反复运用到这个性质1进行分析。

    首先我们证明 (a_{m-1} \% a_m) 是最大值。

    因为 (a_{m-1} \% a_m = a_{m-1})

    证:

    我们把 (a_i \% a_j) 的组合分为 (2) 部分:

    第一部分:(j=m)

    此时 (i in [1, m-1])
    (a_1 \% a_m lt a_2 \%a_m lt cdots lt a_{m-1} \% a_m)
    所以第一部分的最大值是 (a_{m-1} \% a_m = a_{m-1})

    第二部分:(j eq m)
    此时,除数最大是 (a_{m-1}),根据性质1,可得:这一部分的所有答案都小于 (a_{m-1})

    据此可得:最大值即为 (a_{m-1} \% a_m = a_{m-1})

    其次我们要求次大值

    次大值其实就是除了 (a_{m-1}) 以外的最大值。

    第一部分里面除了 (a_{m-1} \% a_m) 以外的最大值就是 (a_{m-2} % a_m = a_{m-2}) 了。

    第二部分我们可以将它拆分成两小部分:

    第2.1部分:(j = m-1) 的部分,这一部分的是 (a_{m-2})(a_m \% a_{m-1}) 的较大值;

    第2.2部分:(j le m-2) 的部分,根据性质1,这一部分的所有答案都 (lt a_{m-2})

    综上所述,我们可以发现,次大值的竞争者只有 (2) 个值:(a_{m-2}) 或者 (a_m \% a_{m-1})

    所以此时次大值即为 (max(a_{m-2}, a_m \% a_{m-1}))

    另附上一张图片方便理解:

    实现代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 200020;
    int n, m, a[maxn], ans;
    int main() {
        cin >> n;
        for (int i = 1; i <= n; i ++) cin >> a[i];
        sort(a+1, a+1+n);
        m = unique(a+1, a+1+n) - a - 1;
        if (m == 1) ans = -1;
        else if (m == 2) ans = a[2] % a[1];
        else ans = max(a[m-2] % a[m], a[m] % a[m-1]);
        cout << ans << endl;
        return 0;
    }
    
  • 相关阅读:
    PAT 甲级 1132 Cut Integer (20 分)
    AcWing 7.混合背包问题
    AcWing 9. 分组背包问题
    AcWing 5. 多重背包问题 II
    AcWing 3. 完全背包问题
    AcWing 4. 多重背包问题
    AcWing 2. 01背包问题
    AcWing 875. 快速幂
    AcWing 874. 筛法求欧拉函数
    AcWing 873. 欧拉函数
  • 原文地址:https://www.cnblogs.com/quanjun/p/12401293.html
Copyright © 2011-2022 走看看