题目链接
题目大意:给球涂颜色,给出了各种颜色需要涂的数量,逐次给每个球涂,要求每种颜色的最后一个球的涂的顺序必须是1,2,3,4,……N,结果较大需要对1 000 000 007取模;
解析:首先最后一个球的颜色必须是N号颜色,那么N号颜色的球还剩data[N]-1个,这data[N]-1个球涂的顺序随意,还有总数(初始设为sum)a=sum-1个位置(最后一个固定),题目给出相同颜色的球相同,这时有组合C(a,data[N]-1)种方式。
对N-1号颜色,最后一个球涂的顺序必须是(注意是最后一个)当前已经涂完N号颜色的序列里的还未放置数据的最后一个,否则不是N-1号颜色,就是比N-1小的颜色,不符合题意。那么对N-1号颜色,还剩data[N-1]-1个球,还有a-1个位置,就有组合C(a,data[N-1]-1)种方式
以此类推
……
……
……
还有一个难点就是取模
因为题目数据多大,而且求组合C中肯定要用到除法,所以就涉及到除法取模公式的运用
逆元: 若,b*b1 % c == 1 则,b1称为b模c的乘法逆元。
在ACM中,许多除法取模都要用到求逆元。 ( a/b ) % c == ( a*b1 ) % c
求一个数逆元模板:
LL power_mod(LL a, LL b, LL mod)///费马小定理求逆元,mod必须为素数,b=mod-2
{
LL ans=1;
while(b)
{
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
// inv2=power_mod(a,mod-2,mod);
}
完整代码:
# include <bits/stdc++.h>
using namespace std;
# define MOD 1000000007
# define MAXN 1010
# define LL long long
int data[MAXN];
int N;
LL power_mod(LL a, LL b, LL mod)///费马小定理求逆元
{
LL ans=1;
while(b)
{
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
// inv2=power_mod(a,mod-2,mod);
}
int C(int a, int b)
{
if(a==b||b==0)
return 1;
LL ans=1;
for(int i=a-b+1; i<=a; i++)
{
ans=(ans%MOD)*(i%MOD)%MOD;
}
LL sum=1;
for(int i=1;i<=b;i++)
{
sum=(sum%MOD)*(i%MOD)%MOD;
}
LL c=power_mod(sum,MOD-2,MOD);
return (ans%MOD)*(c%MOD)%MOD;
}
int main()
{
while(cin>>N)
{
int sum=0;
for(int i=1; i<=N; i++)
{
cin>>data[i];
sum+=data[i];
}
LL ans=1;
for(int i=N; i>=1; i--)
{
LL t=C(sum-1,data[i]-1);
sum-=data[i];
ans=(ans%MOD)*(t%MOD)%MOD;
}
cout<<ans<<endl;
}
return 0;
}