题意:一个大小为 n
的环,选 m
个位置涂黑,要求相邻两个黑点之间至少间隔 k
个白点,问方案数。
题解:
考虑每两个人之间隔了几把椅子。可以发现,一共有M个数,和为N-M,且每个数都>=K.将每个数都减去K-1,即得到:M个正数之和为N-K*M,方案数为C(N-K*M-1,M-1).需要乘以圆排列的N,同时每个方案被算了M次,再除以M。
答案为:C(N-K*M-1,M-1)*N/M。需要用预处理阶乘的方法计算组合数。注意特判M=1的情况。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <vector>
#include <set>
#include <list>
#include <queue>
#include <map>
#include <bitset>
using namespace std;
#define L(i) i<<1
#define R(i) i<<1|1
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-3
#define maxn 1000100
#define MOD 1000000007
int n,m,k;
long long fac[1000010];
long long PowMod(long long a,long long b,long long mod)
{
long long ret = 1;
while(b)
{
if(b & 1)
ret = (ret * a) % mod;
a = (a * a) % mod;
b >>= 1;
}
return ret;
}
long long Get_Fact(long long p)
{
fac[0] = 1;
for(long long i = 1; i <= maxn; i++)
fac[i] = (fac[i-1] * i) % p;
}
long long Lucas(long long n,long long m,long long p)
{
long long ret = 1;
while(n && m)
{
long long a = n % p;
long long b = m % p;
if(a < b)
return 0;
ret = (ret * fac[a] * PowMod(fac[b]*fac[a-b]%p,p-2,p)) % p;
n /= p;
m /= p;
}
return ret;
}
long long inv(long long a,long long m)
{
if(a==1)
return 1;
return inv(m%a,m) * (m-m/a)%m;
}
int main()
{
int t;
scanf("%d",&t);
Get_Fact(MOD);
while(t--)
{
scanf("%d%d%d",&n,&m,&k);
if(m == 1)
{
printf("%d\n",n);
continue;
}
if(n-m*k-1 < m-1)
printf("0\n");
else
printf("%lld\n",((Lucas(n-m*k-1,m-1,MOD)*n%MOD)*inv(m,MOD))%MOD);
}
return 0;
}