C - C HihoCoder - 1701

给定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;
    }
}


posted @ 2018-03-31 19:19  _大美  阅读(205)  评论(0编辑  收藏  举报