Problem
一个袋子中有n个彩球,他们用k种不同的颜色染色。颜色被从1到k编号。同一种颜色的球看成是一样的。现在从袋中一个一个的拿出球来,直到拿完所有的球。对于所有颜色为i (1<=i<=k-1)的球,他的最后一个球总是在编号比他大的球拿完之前拿完,问这样情况有多少种。
样例解释:这个样例中有2个1号颜色的球,2个2号颜色的球,1个3号颜色的球。三种方案是: 1 2 1 2 3 1 1 2 2 3 2 1 1 2 3
Solution
我们先每种颜色各取出来一个,然后按顺序摆放,假设这就是最后一个球,然后按顺序摆其他球。
比如我要摆i号球,i号球一共有a[i]个,i号球的最后一个球,前面已经有sum[i-1]个球,那我们在摆第1个i号球时,有sum[i-1]+1种选择,第2个有sum[i-1]+2种,第a[i]-1个有sum[i-1]+a[i]-1,即sum[i]-1种,最后要除以(a[i]-1)!,因为没有顺序。就是说(sum[i-1]+1)(sum[i-1]+2)...(sum[i-1]+a[i]-1)/(a[i]-1)!,即C[sum[i]-1][a[i]-1]种可能,相乘即可,可以用费马小定理来处理除法。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include<stdio.h> #include<bits/stdc++.h> using namespace std; #define ll long long ll mod=1000000007; ll k,a[1020],ans=1,f1[1020]={1,1},f2[1020]={1,1}; ll speed(ll a,ll b,ll p){ ll cur=a,ans=1; while(b){ if(b&1) ans=ans*cur%p; cur=cur*cur%p; b>>=1; } return ans%p; } int main(){ for(int i=1;i<=1000;i++){ f1[i]=f1[i-1]*i%mod; f2[i]=f2[i-1]*speed(i,mod-2,mod)%mod; } scanf("%lld",&k); for(int i=1;i<=k;i++){ scanf("%lld",&a[i]); a[i]+=a[i-1]; } for(int i=1;i<=k;i++){ int sum=a[i]-1,part=a[i]-a[i-1]-1; ans=ans*f1[sum]%mod*f2[part]%mod*f2[sum-part]%mod; } printf("%lld\n",ans); return 0; }
|