题目大意
将数组以任意顺序划分为数个数组,满足新数组中任意两个相邻元素的和是m的倍数,找数组的最少数量
题解
我们可以将每个数和m取余,如果是0,那么所以0可以放一起,因为他们任意两个数加起来都是m的倍数,如果是m/2并且m是偶数,也可以放一起,他们任意两个数加起来依然是m的倍数,其他的要匹配,如果是1,就和m-1匹配,形成1 m-1 1 m-1…的数组。
#include<cstdio>
#include<algorithm>
#include<map>
#include<set>
using namespace std;
const int MAX=1e5+5;
int num[MAX];
int have[MAX];
int mi[MAX];
int haven,ans;
int main(){
int T,n,m;
scanf("%d",&T);
while(T--){
haven=ans=0;
scanf("%d%d",&n,&m);
ans=n;
for(int i=0;i<n;i++){
scanf("%d",&num[i]);
num[i]%=m;
mi[num[i]]++;
}
sort(num,num+n);
have[0]=-1;
for(int i=0;i<n;i++){
if(num[i]!=have[haven]){
have[++haven]=num[i];
//printf("%d ",have[haven]);
}
}
for(int i=1;i<=haven&&have[i]<=m/2;i++){
int a=mi[have[i]];
int b=mi[m-have[i]];
if(have[i]==0||(have[i]==m/2&&m%2==0)){
ans-=mi[have[i]]-1;
}else if(b){
ans-=2*(a<b?a:b);
if(a==b){
ans++;
}
}
}
for(int i=0;i<=n;i++){
num[i]=have[i]=0;
}
for(int i=0;i<=m;i++){
mi[i]=0;
}
printf("%d\n",ans);
}
}