hihocoder #1698 假期计划 (排列组合+费马小定理+乘法逆元)

Description

小Ho未来有一个为期N天的假期,他计划在假期中看A部电影,刷B道编程题。为了劳逸结合,他决定先拿出若干天看电影,再拿出若干天刷题,最后再留若干天看电影。(若干代指大于0)  每天要么看电影不刷题,要么刷题不看电影;不会既刷题又看电影。并且每天至少看一部电影,或者刷一道题。现在小Ho要安排每天看哪些电影/刷哪些题目,以及按什么顺序看电影/刷题目。注意A部电影两两不同并且B道题目也两两不同,请你计算小Ho一共有多少种不同的计划方案。由于结果可能非常大,你只需要输出答案对1000000009(大质数)取模的结果。只要某个事件(看电影或刷题)发生的日期不同或者在全部事件中的次序不同,就视为不同的方案。

Input

三个整数N, A和B。  

对于30%的数据,N, A, B <= 10  

对于60%的数据, 3 <= N <= 4000, 2 <= A <= 4000, 1 <= B <= 4000  

对于100%的数据,3 <= N <= 100000, 2 <= A <= 100000, 1 <= B <= 100000, A + B >= N

Output

一个整数表示答案。

Sample Input

4 2 2

Sample Output

4
解题思路:假设有i天看电影,则有n-i天刷题。把a部电影分到i(i∈[2,min(a,n-1)],因为至少要留一天刷题,所以i最大为min(a,n-1),最小为2)天看,每天至少一部的方案数为C(a-1,i-1)(考虑隔板法),又因为a部电影两两不同,因此i天看电影的方案数为a!*C(a-1,i-1);同理,把b道题分到n-i天刷,每天至少刷一题的方案数为C(b-1,n-i-1)(b>=n-i),又因为b道题两两不相同,因此n-i天刷题的方案数为b!*C(b-1,n-i-1);又因为i天看电影被分成前后两段,考虑隔板法,还有C(i-1,1)种。因此最终的公式为a!*b!*C(a-1,i-1)*C(b-1,n-i-1)*(i-1)%p。取模大质数-->费马小定理+乘法逆元。
AC代码:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 const LL mod=1e9+9;
 5 const int maxn=100005;
 6 int n,a,b;LL res,A[maxn]={1};//0!=1
 7 LL mod_power(LL x,LL y){//快速幂取模
 8     LL ans=1;x%=mod;
 9     while(y){
10         if(y&1)ans=ans*x%mod;
11         x=x*x%mod;
12         y>>=1;
13     }
14     return ans;
15 }
16 int main(){
17     for(int i=1;i<maxn;++i)//打印阶乘表
18         A[i]=A[i-1]*i%mod;
19     while(cin>>n>>a>>b){
20         res=0;
21         for(int i=2;i<=min(a,n-1);++i)
22             if(b>=n-i)res=(res+(A[a]*A[b]%mod*A[a-1]%mod*A[b-1]%mod*mod_power(A[i-1]*A[a-i],mod-2)%mod*mod_power(A[n-i-1]*A[b-n+i],mod-2)%mod*(i-1)%mod))%mod;
23         cout<<res<<endl;
24     }
25     return 0;
26 }

 

posted @ 2018-08-05 20:42  霜雪千年  阅读(299)  评论(0编辑  收藏  举报