3 1 1 1 2 1 2
Case 1: 15 Case 2: 8HintIn the first case, suppose the colors of the stones Mr. B has are B, G and M, the different patterns Mr. B can form are: B; G; M; BG; BM; GM; GB; MB; MG; BGM; BMG; GBM; GMB; MBG; MGB.
唉……比赛的时候写了好久。。然后100的组合数好像有算错,比赛后瞎搞了一番结果AC了。
题意是输入每种颜色有多少石头,问总共有多少种排法,石头可以不用上。
用插空法做,假设已经放了t个石头,则有t+1个空位,这时候新来的k一种石头就可以放在这t+1个空位上。
假设F(i,j)表示现在有i个空格,要放j个石头。
那么F(i,j)=sum(F(t,j-t)*C(i,t)),0<=t<=min(i,j),C()表示组合数
枚举t表示想将这j个石头放在t个空位里,因此C(i,t)不难理解,就是在i个空位里选t个放,然后将这t个空位每个空位放一个石头,剩下j-t个石头需要再放到这t个空位里,但是允许这t个空位中有部分空位不放,因此就是F(t,j-t),即在这t个空位中放j-t个石头。
比赛的时候的代码,搓死……
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define MOD 1000000007 int a[105]; long long c[10005][105]; long long cc[10005][105]; long long dp[10005]; void C() { int i,j; long long t; for (i=0;i<=10002;i++) { if (i==102) t=1; if (i>102) t=(t*i)%MOD; for (j=0;j<=min(i,102);j++) { if (i==0 || j==0 || i==j) c[i][j]=1; else if (j==102) c[i][j]=t; else c[i][j]=(c[i-1][j-1]+c[i-1][j])%MOD; } } } long long Com(int i,int j) { if (i==1 || j==0) return 1; if (cc[i][j]!=-1) return cc[i][j]; long long ans=0; for (int t=1;t<=min(i,j);t++) { ans=(ans+Com(t,j-t)*c[i][t])%MOD; } cc[i][j]=ans; return ans; } int main() { int i,j,n,m,k,cnt=1; long long ans,tag; memset(cc,-1,sizeof(cc)); C(); while(scanf("%d",&n)!=EOF) { memset(dp,0,sizeof(dp)); dp[0]=1; m=0; for (i=0;i<n;i++) { scanf("%d",&a[i]); for (j=m;j>=0;j--) { for (k=1;k<=a[i];k++) { tag=dp[j]*Com(j+1,k)%MOD; dp[j+k]=(dp[j+k]+tag)%MOD; } } m+=a[i]; } ans=0; for (i=1;i<=m;i++) { ans=(ans+dp[i])%MOD; } printf("Case %d: %I64d\n",cnt++,ans); } return 0; }