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.
题意:
给定n种颜色的石头,每种颜色有num[i]颗,同种颜色的石头不区分。问能构成多少种不同的石头序列(不同的序列是指:1.石头数不同;2.石头数相同,至少一个位置的石头颜色不同)
思路:
首先抽象出状态 dp[ i ][ j ]表示前i种石头构成的长度为j的序列的个数。
那么当处理i种石头时。可以一个都不要。dp[i][j]=dp[i-1][j]。
也可以要k个。那么相当于将这k个个石头放在j个位置上。而将k个石头放在j个位置上的方法数有C[j][k]种。
而以前的j-k个还是按照原排列。所以有dp[i-1][j-k]*C[j][k]种方法。所以。
dp[i][j]=sum(dp[i-1][j-k]*C[j][k])。0<=k<=num[i]。
详细见代码:
#include<algorithm> #include<iostream> #include<string.h> #include<sstream> #include<stdio.h> #include<math.h> #include<vector> #include<string> #include<queue> #include<set> #include<map> using namespace std; const int INF=0x3f3f3f3f; const int maxn=100010; const int mod=1000000007; int C[15000][150],num[150]; __int64 dp[150][15000];//注意数组大小 int main() { int i,j,k,n,cas=1,sum,ans; for(i=0;i<=10010;i++)//注意组合数的范围 { C[i][0]=1; for(j=1;j<=i&&j<=105;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod; } while(~scanf("%d",&n)) { for(i=1;i<=n;i++) scanf("%d",num+i); sum=0; memset(dp,0,sizeof dp); dp[0][0]=1; for(i=1;i<=n;i++) { sum+=num[i]; for(k=0;k<=num[i];k++)//由于利用上层结果。j,k嵌套顺序无关。 for(j=k;j<=sum;j++) dp[i][j]=(dp[i][j]+dp[i-1][j-k]*C[j][k])%mod; } ans=0; for(i=1;i<=sum;i++) ans=(ans+dp[n][i])%mod; printf("Case %d: %d\n",cas++,ans); } return 0; }