hdu 5894 hannnnah_j’s Biological Test

来源:互联网 发布:js创建对象的三种方式 编辑:程序博客网 时间:2024/06/03 19:09

hannnnah_j’s Biological Test

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1789    Accepted Submission(s): 605


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
24 2 65 2 1
 

Sample Output
05
 题意: 给你 一个圆形的桌子 一共有n个座位 有m个人要考试,为了防止作弊 每两个人中间要隔k 个人。问你一共有多少解决方案。
思路: 先看规律 ,对于 n 个座位 如果m+m*k>n 那么就不可能有解决方案,如果 m+k*m==n的话就一共有k种解决方案。
如果 m==1 的话 就有n 中解决方案。 其他的情况我们考虑 首先 从n个座位中减去 k*m 个空隙座位 (也就是这几个座位不能坐人) 那么就剩 n-k*m 个座位 ,首先考虑1号座位 对于一号座位确定了人的话 ,那么久会有 从 n-1 个座位中选出 m-1 个座位, 也就是c(n-k*m-1,m-1) 到这里只是考虑了一号座位 ,要考虑 n 个座位 所以乘以 n 但是会发现 在后面统计的 方案其实有些前边已经出现过,容易发现一共出现了 m 次 那么需要最后除以m 。
对于大数求组合数,我们选择用lucas(卢卡斯定理) 对于 n m 比较大的数 (1e9) 但是p比较小的时候我们选择用fac【】数组预处理出从1 到p的阶乘。。再用lucas定理求解
对于n m 比较小 1e6 但是p比较大 的时候可以用 dp数组打出dp数组(阶乘)
在求解。 (p 为素数)
在运用卢卡斯定理时候通常用到费马小定理 来求逆元。
对于一个数 x 的逆元其实就是 quickpow(x,p-2) 。。p为mod
n m 比较大的情况 代码:
#include <iostream>#include <string.h>#include <stdio.h>using namespace std;#define N 100010long long mod_pow(int a,int n,int p){    long long ret=1;    long long A=a;    while(n)    {        if (n & 1)            ret=(ret*A)%p;        A=(A*A)%p;        n>>=1;    }    return ret;}long long factorial[N];void init(long long p){    factorial[0] = 1;    for(int i = 1;i <= p;i++)        factorial[i] = factorial[i-1]*i%p;}long long Lucas(long long a,long long k,long long p)//求C(n,m)%p p最大为10^5。a,b可以很大!{    long long re = 1;    while(a && k)    {        long long aa = a%p;long long bb = k%p;        if(aa < bb) return 0; //C(aa,bb) 表示 在aa里面取bb个,取法为0;//由于p是素数,所以 a / b % p ,b 对于 mod a 肯定存在逆元        re = re*factorial[aa]*mod_pow(factorial[bb]*factorial[aa-bb]%p,p-2,p)%p;//这儿的求逆不可先处理        a /= p;        k /= p;    }    return re;}int main(){    int a,b,c;    while(cin >> a >> b >> c){        cout << mod_pow(a,b,c)<< endl;    }    return 0;}int main(){    int t;    cin >> t;    while(t--)    {        long long n,m,p;        cin >> n >> m >> p;        init(p);        cout << Lucas(n,m,p) << "\n";    }    return 0;}

对于 n m 不算特别大的情况,例如本题。

代码:
#include<stdio.h>#include<string.h>#include<iostream>#include<algorithm>using namespace std;typedef long long ll;long long n,m,k;const int mod = 1e9+7;ll quickpow(ll a,ll b){    ll fin=1;    ll num=a;    while(b)    {        if(b&1)        {            fin=(fin*num)%mod;        }        num=(num*num)%mod;        b>>=1;    }    return fin%mod;}ll C(ll n, ll m) {    if(m > n) return 0;    ll ans = 1;    for(int i=1; i<=m; i++) {        ll a = (n + i - m) % mod;        ll b = i % mod;        ans = ans * (a * quickpow(b, mod-2) % mod) % mod;    }    return ans;}ll lucas(ll n,ll m){    if(m==0) return 1;    else return C(n % mod, m % mod)* lucas(n / mod, m / mod) % mod;}int main(){    int cas;    cin>>cas;    while(cas--)    {        cin>>n>>m>>k;        if(m==1)        {            printf("%lld\n",n);            continue;        }        if(n<m+m*k){            printf("0\n");            continue;        }        if(n==m+m*k)        {            printf("%lld\n",k+1);            continue;        }        ll num=m;        ll num1=n;        n-=m*k;        n--;  m--;        ll fin=num1*lucas(n,m)%mod;        //printf("%lld\n",fin);        fin=(fin*quickpow(num,mod-2))%mod;        printf("%lld\n",fin);    }    return 0;}


阅读全文
0 0
原创粉丝点击