Atcoder Beginner Contest 156E(隔板法,组合数学)

 1 #define HAVE_STRUCT_TIMESPEC
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 const int N = 5e5 + 7;
 5 const long long mod=1e9+7;
 6 long long fac[N],inv[N];
 7 long long qpow(long long a,long long b){
 8     long long ans=1;
 9     while(b){
10         if(b&1)
11             ans=a*ans%mod;
12         b>>=1;
13         a=a*a%mod;
14     }
15     return ans;
16 }
17 void P(){
18     fac[0]=1;
19     for(int i=1;i<N;i++)
20         fac[i]=fac[i-1]*i%mod;
21     inv[N-1]=qpow(fac[N-1],mod-2);
22     for(int i=N-2;i>=0;i--)
23         inv[i]=inv[i+1]*(i+1)%mod;
24 }
25 long long C(int a,int b){
26     return fac[a]*inv[b]%mod*inv[a-b]%mod;
27 }
28 int n,k;
29 int main() {
30     ios::sync_with_stdio(false);
31     cin.tie(NULL);
32     cout.tie(NULL);
33     P();
34     cin>>n>>k;
35     if(k>=n)//如果k>=n的话,所有1都可以移动,相当于n个相同球放到n个相同盒中,盒子可以空。
36         cout<<C(n+n-1,n-1);//n个球和n个盒子总共有2n-1个空隙,把n个盒子插到空隙里,即为C(2n-1,n)=C(2n-1,n-1)
37     else{
38         long long tot=C(2*n-1,n-1);
39         for(int i=1;i<n-k;i++){//n-k个位置至少为1,容斥减去不足n-k个位置至少为1的情况
40             tot-=1ll*C(n,i)*C(n-1,i-1)%mod;//n个球放到i个盒子里,每个盒子都不为空
41             //先从n个盒子里选出i个盒子,然后n个球之间存在n-1个空隙,把i-1块挡板插到n-1个空隙里,就可以把n个球分为i份且每一份都不为空
42             tot+=mod;
43             tot%=mod;
44         }
45         cout<<tot<<'
';
46     }
47     return 0;
48 }
保持热爱 不懈努力 不试试看怎么知道会失败呢(划掉) 世上无难事 只要肯放弃(划掉)
原文地址:https://www.cnblogs.com/ldudxy/p/12363949.html