Codeforces554C:Kyoya and Colored Balls(组合数学计算+费马小定理)

题意:
有k种颜色,每种颜色对应a[i]个球,球的总数不超过1000
要求第i种颜色的最后一个球,其后面接着的必须是第i+1种颜色的球
问一共有多少种排法
Sample test(s)
input
3
2
2
1
output
3
input
4
1
2
3
4
output
1680
Note

In the first sample, we have 2 balls of color 1, 2 balls of color 2, and 1 ball of color 3. The three ways for Kyoya are:

1 2 1 2 3
1 1 2 2 3
2 1 1 2 3
思路:
首先我们容易想到我们必须要确定每种颜色最后一个球的放法
所有对于最后一种颜色,假设这种颜色有b个球,而总球数为a
那么必然有一个球是放在最后一个位置的,那么剩下的球就是z=C(b-1,a-1)种方法
那么对于倒数第二种球,假设有x个,此时总球数位y=a-b
那么之前已经有z种方法了,而对于每一种放法,此时倒数第二种颜色拿出一个作为最后一个球的话,它对于每种放法必然只有一个固定方法,位置是最后一个没有放球的位置,这样既保证放法符合要求,而剩下的球就有C(x-1,y-1)种放法
然后相乘得到最后一种颜色与最后第二种颜色的方法,以此类推。。
可以使用费马小定理来优化组合数计算

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<stdlib.h>
 5 #include<cmath>
 6 using namespace std;
 7 #define MOD 1000000007
 8 #define ll long long
 9 ll n;
10 ll a[1006];
11 ll fac[1000006];
12 ll pow_mod(ll  a,ll  i)
13 {
14     if(i==0)
15        return 1%MOD;
16     ll t=pow_mod(a,i/2);
17     ll ans=t*t%MOD;
18     if(i%2==1)
19       ans=ans*a%MOD;
20       return ans;
21 }
22 ll work(ll m,ll i)
23 {
24     return ( (fac[m]%MOD)* ( pow_mod(fac[i]*fac[m-i]%MOD ,MOD-2)%MOD))%MOD;
25 }
26 
27 int main()
28 {
29     fac[0]=1;
30     for(int i=1;i<1000006;i++)
31           fac[i]=(fac[i-1]*i)%MOD;
32     ll ans=1;
33     ll sum=0;
34     scanf("%I64d",&n);
35     for(int i=1;i<=n;i++)
36     {
37         scanf("%I64d",&a[i]);
38         sum+=a[i];
39     }
40     for(int i=n;i>=1;i--)
41     {
42         ans=ans*work(sum-1,a[i]-1)%MOD;
43         sum-=a[i];
44     }
45     printf("%I64d
",ans);
46     return 0;
47 }
View Code
 
原文地址:https://www.cnblogs.com/UniqueColor/p/4735115.html