您的位置:首页 > Web前端 > JavaScript

hdu-5894-hannnnah_j’s Biological Test(Lucas定理+乘法逆+组合数)

2016-09-29 13:45 721 查看
hannnnah_j’s Biological Test

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)

Problem Description

hannnnah_j is a teacher in WL High school who teaches biology.

One day, she wants to test m students, thus she arranges n different seats around a round table.

In order to prevent cheating, she thinks that there should be at least k empty seats between every two students.

hannnnah_j is poor at math, and she wants to know the sum of the solutions.So she turns to you for help.Can you help her? The answer maybe large, and you need to mod 1e9+7.

 
Input

First line is an integer T(T≤1000).

The next T lines were given n, m, k, respectively.

0 < m < n < 1e6, 0 < k < 1000

 
Output

For each test case the output is only one integer number ans in a line.

 

Sample Input

2

4 2 6

5 2 1

 
Sample Output

0
5

题意:

给一个m个学生在长度为n的环形摆放的座位安排座位,要求相邻两个学生座位之间的距离至少是k,交换两个学生后的摆放和原来一样视为同种方案,求总方案数%1e9+7。

题目链接:hannnnah_j’s Biological Test

解题思路:

先从n个座位选一个出来,符合条件的方案,必须有k*m个空座位,那么接下来只需从n-1+k*m个座位中选出m-1个同

学的座位即可,第一个位置有n种选法,但因为学生都是一样的,同种方案会被不同的学生选到,即选了m次,删去重

复答案为n*C(n-k*m-1, m-1)/m % (1e9+7)。

计算组合数取模可以套用Lucas模板,在模mod下,a/b %mod 与 a*(b)的逆 同余数,用inv(m,mod)求解模mod下m的

逆(Lrj 训练指南122)。

代码:

#include<cstdio>

using namespace std;
typedef long long LL;
const int N = 1e6+5;
const LL mod = 1e9+7;
LL fac[N+10];

LL pow_mod(LL x, LL n)//快速幂取模
{
LL sum = 1;
while(n) {
if(n & 1) sum = sum * x % mod;
x = x * x % mod;
n >>= 1;
}
return sum;
}

void init()//初始化所需要的阶乘
{
fac[0] = 1;
for(int i = 1;i <= N;i++)
fac[i] =fac[i-1] * i % mod;
}

LL Lucas(LL n, LL m)//Lucas定理,计算C(n,m)%mod
{
LL ans = 1;
while(n && m) {
LL a = n % mod, b = m % mod;
if(a < b) return 0;
ans = ans * fac[a] * pow_mod(fac[b]*fac[a-b] % mod, mod-2) % mod;
n /= mod;
m /= mod;
}
return ans;
}

void exd_gcd(LL a, LL b, LL& d, LL& x, LL& y)//拓展欧几里得解方程ax+by=gcd(a,b);
{
if(!b) {
d = a;
x = 1;
y = 0;
}
else {
exd_gcd(b, a%b, d, y, x);
y -= x*(a/b);
}
}
LL inv(LL a, LL n)//计算模n下a的逆元,如果不存在,返回-1
{
LL d, x, y;
exd_gcd(a, n, d, x, y);
return d == 1? (x+n)%n : -1;
}

int main()
{
int T;
LL n, m, k;
init();
scanf("%d",&T);
while(T--) {
scanf("%I64d%I64d%I64d",&n, &m, &k);
if(m == 1) {
printf("%I64d\n",n);
continue;
}
printf("%I64d\n",(n * Lucas(n-k*m-1, m-1) % mod) * inv(m, mod) % mod);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息