一个小练习

来源:互联网 发布:大数据算法设计与分析 编辑:程序博客网 时间:2024/05/22 04:59

【问题描述】
n根木棍在地面上摆成一排,从中选择k根木棍,使得任意两个被选的木棍之间至少隔了m根木棍,有多少种选法?
【输入描述】(A.in)
第一行包含3个整数n、k、m,分别为题目所描述的
【输出描述】(A.out)
输出答案,由于答案很大,需要mod1000000007.
【输入样例】1000 100 5
【输出样例】444301345
【数据范围】
对于30%的数据 : 1<=n<=10,1<=k<=10,0<=m<=10
对于100%的数据: 1<=n<=1000,1<=k<=1000,0<=m<=1000

【问题分析】
分析题意得,总木棍数至少需要(k-1)*m+k根;然而总有一些地方是不能放木棍的,这些木棍有(k-1)*m根,需要空出来,把它们减掉,剩下的就是一个排列组合的问题。

【注意事项】
1. 如果剩下的木棍少于k根,那么需要特判,方案数为0;
2. 求组合数的公式如下:

这里写图片描述
3. 由于答案很大,我们需要对其取模,那么就需要用到乘法逆元,这里既可以分别求出m! 与(n-m)!的乘法逆元再向乘,也可以先乘后求逆元;
4. 逆元是关于模数的,所以快速幂要算1000000007-2次方,别误认为是关于n!-2;
5. 输入输出!!

以下代码:

#include<iostream>#include<cstdio>#include<cstring>#define mod 1000000007int line,chose,ge;long long jc[1010];using namespace std;long long jcheng(int x){  long long ans=1;     for(int i=2;i<=x;i++)     {        if(jc[i]!=0)            ans=jc[i];         else          {            ans=(ans%mod * i%mod)%mod;            jc[i]=ans;          }     }  return ans;   }long long ni(long long x){    long long ans=1;    long long m=mod-2;    while(m>0)      {        if(m & 1) ans=(ans* (x%mod))%mod;        x=(x*x)%mod;        m>>=1;      } return ans%mod;      }long long work(int m,long long n){    long long t1,t2,t3,t4;    t1=jcheng(n);    t2=jcheng(m);    t3=jcheng(n-m);    t4=ni((t2*t3)%mod);    return (t1%mod*t4%mod)%mod;}int main(){ freopen("A.in","r",stdin); freopen("A.out","w",stdout);     memset(jc,0,sizeof(jc));  jc[0]=1;jc[1]=1;  scanf("%d%d%d",&line,&chose,&ge);  long long b=line- ge*(chose-1);  if(b<chose||line<chose)//¿Û•Öµã£¡    {    printf("0");  return 0;  }    printf("%lld",work(chose,b)%mod); return 0;   }
原创粉丝点击