给定N个整数A1, A2, ... AN,小Hi希望从中选出M个整数,使得任意两个选出的整数的差都是K的倍数。
请你计算有多少种不同的选法。由于选法可能非常多,你只需要输出对1000000009取模的结果。
Input
第一行包含三个整数N、M和K。
第二行包含N个整数A1, A2, ... AN。
对于30%的数据,2 ≤ M ≤ N ≤ 10
对于100%的数据,2 ≤ M ≤ N ≤ 100 1 ≤ K, Ai ≤ 100
Output
一个整数表示答案。
Sample Input
5 3 2
1 2 3 4 5
Sample Output
1
先用桶排序的方法把n个数的余数统计一下,对每一个余数的个数大于m的数求C(n,m);
C(n,m)的求法不能简单的阶乘取余在相除。取余之后的数在做除法和减法会导致答案出错,除以一个数等于乘以这个数的逆元,
所以用逆元可以避免除法。
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>
#define maxn 10005
#define inf 0x3f3f3f3f
#define ll long long
#define mod 1000000009
const double eps=1e-8;
const double PI=acos(-1.0);
using namespace std;
ll a[maxn];
ll b[maxn];
ll fac[maxn];
void init(){
ll i;
fac[0]=1;for(int ll i=1;i<105;i++){
fac[i]=fac[i-1]*i%mod;
}
}
ll exgcd(ll a,ll b,ll &x,ll &y){
if(!b){x=1;y=0;return a;}
ll d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
ll inv(ll a,ll n){
ll x,y;
exgcd(a,n,x,y);
return (x+n)%n;
}
ll c(ll n,ll m){
return fac[n]*inv(fac[m]*fac[n-m]%mod,mod)%mod;
}
int main(){
ll n,m,k;
while(~scanf("%lld%lld%lld",&n,&m,&k)){
memset(b,0,sizeof(b));
memset(a,0,sizeof(a));
init();
for(int i=0;i<n;i++){
scanf("%lld",&a[i]);
b[a[i]%k]++;//余数相同的个数
}
ll ans=0;
for(int i=0;i<k;i++){
if(b[i]<m)continue;
else{
if(m==b[i])ans+=1;
else{
ans+=c(b[i],m);//求c(n,m);
}
ans%=mod;
}
}
ans%=mod;
cout<<ans<<endl;
}
}