题解(by 石二lyh orz)
一组数两两之差可以整除m,当且仅当它们在模m的剩余系意义下相等。对于每个数a[i],将其加入a[i]%m的代表集合中,判断0~m-1是否有一个集合的个数大于等于k即可。输出字典序最小的方案时,只需要比较所有满足题意的集合中的最小值,最小值最小的集合即为答案,排序输出前k个即可。
时间复杂度o(n+klogk)
代码
//by ziwan
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
const int MAX_N=1e6;
using namespace std;
struct nums{
int a,p;//a为数值 p为%m意义下的剩余系
}num[MAX_N];
bool cmp(nums x,nums y){
return x.a<y.a;
};
int n,m,k,cnt[MAX_N],bl,bol[MAX_N],ans;
int main()
{
cin>>n>>k>>m;//给定n个数 选出恰好k个数 两两之差可以被m整除
for(int i=1;i<=n;i++)
{
cin>>num[i].a;
num[i].p=num[i].a%m;
cnt[num[i].p]++;//给剩余系下存的num计数
}
sort(num+1,num+n+1,cmp);
for(int i=0;i<m;i++)
if(cnt[i]>=k)
{
bl=1;
bol[i]=1;
}
if(bl==0) cout<<"No"<<endl;
else
{
cout<<"Yes"<<endl;
for(int i=1;i<=n;i++)
{
if(bol[num[i].p]) {
ans=num[i].p;
break;}
}
int tot=0;
for(int i=1;i<=n;i++)
{
if(num[i].p==ans)
{
cout<<num[i].a<<" ";
if(++tot==k) break;
}
}
}
return 0;
}