代码源:555、整齐的数组2

243 阅读3分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路 logo.png

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

题目描述

这是3月15日代码源div1的每日一题,对应cf分数1900。

知识点:最大公因数+哈希表

整齐的数组2 - 题目 - Daimayuan Online Judge

Polycarp 有一个长度为 n 的数组 a1,a2,...,an(n 是偶数)。Polycarp 还得到了一个正整数 k,他开始对数组 a 做如下操作:选择一个下标 i (1≤i≤n)使 ai 减去 k。

在 Polycarp 进行若干次操作后(可能 0 次),数组 a 中的数至少有一半都变成相同的了。请你找到最大的符合要求的 k,如果 k 可以为任意大,请输出 −1−1。

输入格式

第一行一个整数 t,表示测试单元的个数。

接下来每个测试单元有两行。第一行包含一个偶数 n。第二行包含 n 个整数 a1,a2,...,an。

输出格式

对于每个测试单元输出单独一行一个整数 k (k≥1)—— Polycarp 能用来对数组进行操作的最大的数,或者 −1 —— 如果 kk 能任意大的话。

样例输入

4
6
48 13 22 -15 16 35
8
-1 0 1 -1 0 1 -1 0
4
100 -1000 -1000 -1000
4
1 1 1 1

样例输出

13
2
-1
-1

数据规模

所有数据保证 1≤t≤10,4≤n≤40(n 是偶数),−10^6≤ai≤10^6,并且 n 的总和不超过100。

问题解析

这题是整齐的数组 - 题目 - Daimayuan Online Judge的进阶,区别就是上一题要全部相等,这里只要有一半相等就行了。做法总体和上一题差不多,细节就有区别了。

上一题我们把数变成相等的问题转化成了数变成数组中最小数的问题,那么在这里也是一样的,我们还是取一个最小值然后把其它数变成这个最小值就可以了,但是题目现在说只要我们转一半的数组就可以了,那这样k的选择显然多了很多。我们从第1个数枚举到第n个数,“假设”这个数是最小的数,然后我们遍历数组,把所有大于它的数都记下来,同时也要记录下等于这个“最小值”的个数,如果这个“最小值”出现了n/2次,那说明k不管为什么,都至少有一半的数相等,直接输出-1。我们记下来的这些数+“最小值”的个数就组成了我们的数组,此时的问题就是,把这个数组的其他值都变成这个最小值,然后我们就用第一题的方法写就行。

关于第一题的做法感兴趣的也可以移步代码源:554、整齐的数组 - 掘金 (juejin.cn)

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<map>

int main() {
    int t;
    cin >> t;
    while (t--)
    {
        int n, k = 0;
        cin >> n;
        vector<int>v(n + 1);

        bool flag = true;
        for (int i = 1; i <= n; i++)
            cin >> v[i];
        for (int i = 1; i <= n; i++)
        {
            map<int, int>mymap;
            if (!flag)break;
            int ans = 0,res=0;
            for (int j = 1; j <= n; j++)
            {
                if (v[j] > v[i])
                {
                    mymap[v[j] - v[i]]++;
                    res++;
                }
                else if (v[j] == v[i])
                {
                    ans++;
                }
                if (ans >= n / 2)
                {
                    cout << -1 << '\n';
                    flag = false;
                    break;
                }
            }
            if (res < n / 2 - ans)continue;
            map<int, int>gcd_num;
            for (auto j : mymap)
            {
                for (int l = 1; l * l <= j.first; l++)
                {
                    if (j.first % l == 0)
                    {
                        gcd_num[l] += j.second;
                        gcd_num[j.first / l] += j.second;
                    }
                }
            }
            for (auto j : gcd_num)
            {
                if (j.second + ans >= n / 2)k = max(k, j.first);
            }
        }
        if (flag)
        {
            cout << k << '\n';
        }
    }
    return 0;
}