人群中钻出个光头

人群中钻出个光头

TimeLimit:1000MS  MemoryLimit:256MB
64-bit integer IO format: %lld
 
Problem Description

人话:有m+1种物品,每种物品的数量无限。从中抽取n个物品,有多少种不同的取法。

两个取法的被认为是不同的,当且仅当存在至少一种物品在两个取法中的数量不同。

image.png

PDF题面

Input

有多组样例,每组样例一行,包含两个整数 n, Mn, M,用空格隔开。

Output

每组样例输出一行,所求抽法数对 $10^9+7$ 取余后的值。

SampleInput
3 1
233 233

SampleOutput
4
734436443



题意的话见人话部分就好了。。。。。,这题其实就是求一个组合数,从m钟物品中取n个物品,就是多重集合排列问题(x1+x2+...+xm=n),用m-1个隔板把n个物品分隔开就好,即C(n+m-1,n),
由于m是从0-m,有m+1种,那么ans=C(n+m,n);

多重排列问题:

线性方程 x1 + x2 + ... + xk = r 一共有多少组非负整数解?

解答:上述不定方程的非负整数解对应于下述排列

1...101...1 01...1 0 ...... 01...1

x1 个    x2 个   x3 个   ......  xk 个

其中 k-1个 0 将 r 个 1 分成k段, 每段含1的个数分别为 x1, x2, ..., xk, 

很明显这个排列是多重集合 S = { r * 1, (k-1)* 0 }的全排列

即:P(r+k-1; r*1, (k-1)*0) = (r+k-1)! / ( r! * (k-1)! ) = C( r+k-1, r),即从k类元素中选r个的种类;

这一题,求组合数的话,要提前预处理2e6的阶乘以及逆元,不然会超时;

 1 #include<stdio.h>
 2 #define ll long long
 3 const ll mod=1e9+7;
 4 const ll maxn=2e6+7;
 5 ll quick_pow(ll a,ll b)
 6 {
 7     ll ans=1;
 8     while(b)
 9     {
10         if(b&1)
11             ans=ans*a%mod;
12         b>>=1;
13         a=a*a%mod;
14     }
15     return ans;
16 }
17 ll fac[maxn+7],inv[maxn+7];///fac阶乘,inv阶乘的逆元也就是倒数
18 void init()
19 {
20     fac[0]=fac[1]=1;
21     for(int i=2;i<=maxn;i++)
22         fac[i]=i*fac[i-1]%mod;
23      
24     inv[maxn]=quick_pow(fac[maxn],mod-2);
25     for(int i=maxn-1;i>=0;i--)
26         inv[i]=inv[i+1]*(i+1)%mod;
27        
28     return ;
29 }
30 ll C(ll n,ll m)
31 {
32     return fac[n]%mod*(inv[m]%mod*inv[n-m]%mod)%mod%mod;
33 }
34 int main()
35 {
36     init();
37     ll n,m;
38     while(~scanf("%lld",&n))
39     {
40         printf("%lld\n",fac[n]);
41     }
42     return 0;
43 }
View Code

猜你喜欢

转载自www.cnblogs.com/yuanlinghao/p/10519460.html
今日推荐