HDU 5894 hannnnah_j’s Biologica(lucas定理求組合數+乘法逆元)——2016 ACM/ICPC Asia Regional Shenyang Online

此文章可以使用目錄功能喲↑(點擊上方[+])

 HDU 5894 hannnnah_j’s Biologica

Accept: 0    Submit: 0
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

 Problem Idea

解題思路:

【題意】
n個位置圍成環,m個人坐,要求相鄰兩個人之間必須至少隔k個位置

問有多少種坐法,結果對1e9+7取模

【類型】
lucas定理求組合數+乘法逆元
【分析】
其實此題可以這麼理解


假定一個人已經坐在了某個位置,如圖所示

那還剩下n-1個位置,而要求相鄰兩人之間必須隔k個位置,所以m個人就有m*k個位置不能坐

那剩下的位置數爲n-1-m*k,由於一個人已經坐好,那我需要從這些剩下的位置中挑選出m-1個位置供剩下的m-1個人就坐

故組合數爲C(n-m*k-1,m-1)

然後因爲有n個位置,所以第一個人位置的選法就有n種

再考慮此題中每個人都是一樣的,即不同方案僅僅是坐的位置序列不同,那上述做法會重複計算m次

比如有3個人,假設他們坐的位置是(2,4,7),那麼,(4,2,7),(7,2,4)是重複計算的

故方案數的最終式子應爲[C(n-m*k-1,m-1)*n/m]%1000000007

那求解組合數不用想肯定得用lucas定理,畢竟n和m有點大,直接打表已經存不下結果,且會超時

而除法取模部分,考慮到1000000007是質數,且m<1000000007,所以gcd(m,1000000007)=1,故可以直接採取乘法逆元

【時間複雜度&&優化】

題目鏈接→HDU 5894 hannnnah_j’s Biologica

 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-9
#define LL long long
#define PI acos(-1.0)
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 1000005;
const int M = 100005;
const int inf = 1000000007;
const int mod = 1000000007;
__int64 fac[N];
void init()//預處理階乘
{
    fac[0]=1;
    for(int i=1;i<=N;i++)
        fac[i]=i*fac[i-1]%mod;
}
__int64 pow_mod(__int64 a,__int64 b)
{
    __int64 s=1;
    a=a%mod;
    while(b)
    {
        if(b&1)
            s=s*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return s;
}
__int64 C(int n,int m)
{
    if(m>n)
        return 0;
    return  fac[n]*pow_mod(fac[m]*fac[n-m]%mod,mod-2)%mod;
}
__int64 Lucas(int n,int m)
{
    if(m==0)
        return 1;
    return C(n%mod,m%mod)*Lucas(n/mod,m/mod)%mod;
}
__int64 Quick_Mod(int a,int b)//快速冪
{
    __int64 res = 1,term = a % mod;
    while(b)
    {
        if(b & 1) res = (res * term) % mod;
        term = (term * term) % mod;
        b >>= 1;
    }
    return res;
}
int main()
{
    int t,n,m,k;
    init();
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&n,&m,&k);
        printf("%I64d\n",((Lucas(n-m*k-1,m-1)*n)%mod)*Quick_Mod(m,mod-2)%mod);
    }
    return 0;
}
菜鳥成長記
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章