【模拟】蓝桥杯真题 2018初赛 倍数问题

题目描述

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

输入
第一行包括 2 个正整数 n, K。
第二行 n 个正整数,代表给定的 n 个数。
1 <= n <= 10^5, 1 <= K <= 10^3,给定的 n 个数均不超过 10^8。
输出
输出一行一个整数代表所求的和。
样例输入

4 3
1 2 3 4

样例输出

9

思路

1、第一反应暴力,绝对t(我还试了一下,只能过30%)
2、找规律,其实与倍数有关,就只需要关心三个数的余数就够了,只要三个数的余数和能整除k,三个数的和也就能整除k了
3、用一个二维vector可以记录下每个数的余数情况(0-k-1),在对每个余数0-k-1的数进行由大到小排序(每个余数最多只需要用到前三个)
4、只需要用二重循环模拟取数,第三个数由前两个余数可求得,例如前两个余数为i和j,第三个则为k-(i+j)%k,详细见代码

代码

#include<bits/stdc++.h>
#define N 1001
using namespace std;

long long n, k, x;
long long ans = 0;

vector<vector<long long> > a(N);

int cmp(long long x, long long y){
    return x>y;
}

int main(){

    cin>>n>>k;

    for(int i=0; i<n; i++){
        cin>>x;

        a[x%k].push_back(x);
    }

    //对0-k-1的数进行从大到小排序
    for(int i=0; i<k; i++)
        sort(a[i].begin(), a[i].end(), cmp);

    //二重循环模拟取数
    for(int i=0; i<k; i++){
        for(int j=0; j<k; j++){
            //第三个余数
            int t = k-(i+j)%k;

            //如果三个余数都一样
            if(t==i && t==j){
                //保证该余数存在三个数,否则无法取到这种情况
                if(a[i].size()>=3)
                    ans = max(ans, a[i][0]+a[i][1]+a[i][2]);
            }
            //如果i和t一样,和j不同,下面以此类推
            else if(t==i){
                if(a[i].size()>=2 && a[j].size())
                    ans = max(ans, a[i][0]+a[i][1]+a[j][0]);
            }else if(t==j){
                if(a[j].size()>=2 && a[i].size())
                    ans = max(ans, a[j][0]+a[j][1]+a[i][0]);
            }else if(i==j){
                if(a[i].size()>=2 && a[t].size())
                    ans = max(ans, a[i][0]+a[i][1]+a[t][0]);
            }else{
                if(a[i].size() && a[j].size() && a[t].size())
                    ans = max(ans, a[i][0]+a[j][0]+a[t][0]);
            }
        }
    }

    cout<<ans<<endl;

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值