map_计蒜客T1271 完美K倍子数组
题目大意
寻找数组中任意两个两个数之和是 k 的倍数的最长完美子数组B
选出最少 2 个数,满足 他们相加其和是K的倍数,找到满足条件的一组;
解题思路
如果存在B,有两种情况:
- 它们都是K的倍数,对K取余为0,或者余数为K/2的数字的数量大于等于2
- 任意两个数对K取余数,它们的余数相加是K的倍数,那么数组B的长度为2
如果不存在B,输出 -1。
- 遍历数组,用map记录每个数字模 k 的余数出现次数;同时实时检查是否存在余数互补的情况,标记
f=1 - 统计余数为 0和(k为 偶数时)余数是 k/2 的个数
- 判断:
- 如果余数 0 数量≥2 或者 余数 k/2 数量≥2 → 输出该数量
- 否则如果存在普通互补余数对 → 输出 2
- 全都不满足 → 输出 - 1
样例输入
5 3
1 3 2 3 6
样例输出
3
完整代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main(){
int n,k;
cin>>n>>k;
// mp[余数] = 该余数出现的数字个数
map<int,int>mp;
int a;
// f标记:是否找到一对余数s 和 k-s(s≠0,s≠k/2)
int f=0;
for(int i=0;i<n;i++){
cin>>a;
int s=a%k; // 求当前数字模k的余数
mp[s]++; // 余数计数+1
if(f==0){ // 还没找到配对时才判断
// 寻找互补余数 k-s
if(mp[k-s]!=0){
f=1;
}
}
}
int ans1=mp[0]; // 余数0的数字:任意两个相加都是k倍数
int ans2=0;
if(k%2==0){
ans2=mp[k/2]; // k偶数时,余数k/2两个相加 = k
}
// 候选最大值:最多的一类特殊余数数量
int ans=max(ans1,ans2);
if(ans>=2)
cout<<ans; // 存在≥2个余数0 或 ≥2个余数k/2,直接输出数量
else if(f==1){
cout<<2; // 存在一对 s 和 k-s,输出2
}
else
cout<<-1; // 没有任何满足条件的数对
return 0;
}