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