题意:有n种颜色的球,每个球有a[i]个,每种颜色的球都是一样的,然后开始取球,要求编号小的球要比编号大的球先取完,即每种颜色最后取得顺序是递增的,就是要先取完第一种最后一个才能开始取第二种最后一个,前面的怎样都行。
解法:推公式,作为一个acm菜比,一个公式推了一个小时,试了各种方法,最后用的插空法,先拿出每种球各一个放在那,作为最后的顺序,假设剩余的每种球都是不一样的,那么对于第一种剩余的球,只能往1号球前面插空,第一个有一种插法,第二个就有两种插法,对于第二种球,只能插在2号球前面,以此类推。
注意,求模用到了乘法逆元
AC代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#define mod 1000000007
using namespace std;
long long k,c[1005];
long long cnm(long long x)
{
long long ans = 1;
for(int i = 1; i <= x; i++)
{ans *= i;
ans%=mod;}
return ans;
}
long long chengfaniyuan(long long a,long long b,long long c)
{
long long x1,x2,x3,y1,y2,y3,t1,t2,t3,k,ni;
if(b > c){x2 = b; b = c; c = x2;}
x1 = 1,x2 = 0,x3 = c;
y1 = 0,y2 = 1,y3 = b;
while(1)
{
if(y3 == 0) {ni = 0;break;}
if(y3 == 1) {ni = y2;break;}
k = x3/y3;
t1 = x1-k*y1,t2 = x2-k*y2,t3=x3-k*y3;
x1 = y1,x2=y2,x3=y3;
y1=t1,y2=t2,y3=t3;
}
if(ni < 0) ni+=mod;
return a*ni%c;
}
int main(){
long long tot = 1;
scanf("%lld",&k);
for(int i = 0; i < k; i++)
{scanf("%lld",&c[i]);
c[i] --;}
long long tem = 0;
for(int i = 0; i < k; i++)
{
tem++;
for(int j = 0; j < c[i]; j++)
{tot *= tem++;
tot%=mod;}
}
long long div = 1;
for(int i = 0; i < k; i++)
{div*=cnm(c[i]);
div%=mod;}
printf("%lld\n",chengfaniyuan(tot,div,mod));
}