这次到渣渣问桶桶了。。。
准备给你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
思路
- 题意:给我们n个数,让我们找出 由m个数组成的方案数(组成的这m个数的中的任意两个之间相差都要是k)
- 分析:让这个n个数 都取余k,那么余数相同的 数之间必定相差都是k,所以我们可以同 桶排 中的桶 去统计 在这个n个数中余数为1到k-1的数的个数,之后对于 对于每个余数我们考虑:看它的个数是否大于等于m,如果大于的话我们就用数学中的 排列组合知识 去求方案数。
- 特别注意在 排列方案数 C x y C_x^y Cxy的时候,时候我们不能 乘完再除,这样有可能超 long long,所以要边乘边除 主要代码如下
ll ans = 1
for(int i = 1; i <= y; i ++)
ans = ans*(x + 1 - i) / i ;
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
const ll mod = 1000000009;
ll work(ll n, ll m)
{
ll res = 1;
/* for(int i = n; i >= n - m + 1; i --) */
/* res *= i; */
/* for(int i = 1; i <= m; i ++) */
/* res /= i; */
for(int i = 1; i <= m; i ++)
res = res*(n + 1 - i)/i;
return res;
}
int main()
{
/* freopen("A.txt","r",stdin); */
ll n, m, k;
scanf("%lld %lld %lld", &n, &m, &k);
int x;
int bar[105] = {0};
for(int i = 1; i <= n; i ++)
{
scanf("%d", &x);
bar[x % k] ++;
}
ll ans = 0;
for(int i = 0; i < k; i ++)
{
if(bar[i] >= m)
ans += work(bar[i], m), ans %= mod;
}
printf("%lld\n", ans);
return 0;
}