倍数问题(2018蓝桥杯)

题目描述:

众所周知,小葱同学擅长计算,尤其擅长计算一个数是否是另外一个数的倍数。
但小葱只擅长两个数的情况,当有很多个数之后就会比较苦恼。
现在小葱给了你 n 个数,希望你从这 n 个数中找到三个数,使得这三个数的和是 K 的倍数,且这个和最大。数据保证一定有解。

输入格式:

从标准输入读入数据。

第一行包括 2 个正整数 n, K。
第二行 n 个正整数,代表给定的 n 个数。

 

输出格式:

输出到标准输出。
输出一行一个整数代表所求的和。

 

示例:

输入:
4 3
1 2 3 4

输出:
9

 

数据约定:

对于 30% 的数据,n <= 100。
对于 60% 的数据,n <= 1000。
对于另外 20% 的数据,K <= 10。
对于 100% 的数据,1 <= n <= 10^5, 1 <= K <= 10^3,给定的 n 个数均不超过 10^8。


资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms


请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

注意:
main函数需要返回0;
只使用ANSI C/ANSI C++ 标准;
不要调用依赖于编译环境或操作系统的特殊函数。
所有依赖的函数必须明确地在源文件中 #include <xxx>
不能通过工程设置而省略常用头文件。

 

题目分析:

本题可以使用暴力枚举,枚举分析所有的数,若分析得出结果值最大值输出;

但是若纯 暴力时间复杂度将会变得十分大,

所以可以先分析所有数据,只保留余数相同的最大的三个数。然后逐个枚举得出结果。

 

代码:

c++:

#pragma warning(disable:4996)
#include<iostream>
#include<memory>
#include<vector>
#include<unordered_map>
typedef long long ll;
inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch>'9') {
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
int main()
{
    int i, num;
    int k, flag = 1;
    int b[1001][3];//用于判断余数相同的三个数
    memset(b, -1, sizeof(b));
    std::unordered_map<int, int>c;//map的key值存放余数,value值存放余数对应二维数组b的下标
    scanf("%d %d", &i, &num);


    while (i--)
    {
        k = read();
        int kk = k % num;
        if (!c[kk])
        {
            c[k % num] = flag;//将余数所在的位置给map的映射
            b[flag][0] = k;
            flag++;
        }
        else//若该余数有值,则替换其中最小值或者加入其中
        {
            int inte = k;
            for (int z = 0;z < 3;z++)
                if (b[c[kk]][z] < inte)
                    inte ^= b[c[kk]][z] ^= inte ^= b[c[kk]][z];
        }
    }
    //枚举
    ll ans = 0, v1, v2, v3;
    for (auto iter1 = c.begin();iter1 != c.end();iter1++)
    {
        for (auto iter2 = c.begin();iter2 != c.end();iter2++)
        {
            int mainder = (2 * num - iter1->first - iter2->first) % num;
            v1 = b[iter1->second][0];
            if (iter1->first == iter2->first)
            {
                v2 = b[iter1->second][1];
                if (iter1->first == mainder)
                    v3 = b[iter1->second][2];
                else
                    v3 = b[mainder][0];
                if (v3 == -1 || v2 == -1) continue;
            }
            else
            {
                v2 = b[iter2->second][0];
                if (iter1->first == mainder) v3 = b[iter1->second][1];
                else if (iter2->first == mainder) v3 = b[iter2->second][1];
                else v3 = b[mainder][0];
                if (v3 == -1 || v2 == -1) continue;
            }
            ll tem = v1 + v2 + v3;
            if (ans < tem)ans = tem;
        }
    }
    printf("%lld", ans);
    return 0;
}

 

 
posted @ 2021-01-20 18:44  Carrout  阅读(298)  评论(0编辑  收藏  举报