B - 来找一找吧 HihoCoder - 1701
题目:
这次到渣渣问桶桶了。。。
准备给你n个数a1, a2, ... an,桶桶你能从中找出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
题解:
因为“任意两个数的差是k的倍数,那么两个数取余k后相等”,所以只需要统计一下取余k之后有多少数等于x(1<=x<k)
假设这个数是ans,然后从ans里面挑出来m个数就行(也就是排列组合)
我们这里用的第二个公式
但是排列组合要求阶乘,为了防止爆long long,我们要边乘边除(具体见代码)
代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #include<algorithm> 5 #include<queue> 6 #include<vector> 7 #include<map> 8 using namespace std; 9 const int INF=0x3f3f3f3f; 10 const int maxn=110; 11 const int mod=1000000009; 12 typedef long long ll; 13 ll v[maxn]; 14 int main() 15 { 16 ll n,m,k; 17 while(~scanf("%lld%lld%lld",&n,&m,&k)) 18 { 19 memset(v,0,sizeof(v)); 20 ll temp1,temp2,ans=0; 21 for(ll i=0; i<n; i++) 22 { 23 ll x; 24 scanf("%lld",&x); 25 v[x%k]++; 26 } 27 for(ll i=0; i<k; i++) 28 { 29 temp1=1; 30 temp2=1; 31 if(v[i]<m) 32 continue; 33 // for(ll j=m+1; j<=v[i]; j++) 34 // { 35 // temp1=temp1*j; 36 // } 37 // for(ll j=m+1; j<=v[i]-m; j++) 38 // { 39 // temp2=temp2*j; 40 // } 41 // temp1/=temp2; 42 for(ll j=m+1;j<=v[i];j++) //这个for循环就是分子的阶乘 43 { 44 temp1=temp1*j; 45 //注意要加判断条件temp1%temp2==0,只有这样才会保证结果正确 46 while (temp1%temp2==0 && temp2<=(v[i]-m)) //这个temp2就是分母的阶乘 47 { 48 temp1=temp1/temp2; 49 temp2++; 50 } 51 } 52 53 ans+=(temp1%mod); 54 } 55 printf("%lld\n",ans); 56 } 57 return 0; 58 }