hdu 4248 A Famous Stone Collector
首先发现一个很头痛的问题,下面是2个求排列组合的代码
1 memset(C,0,sizeof(C)); 2 for(int i=0;i<10010;i++) 3 { 4 C[i][0]=1; 5 for(int j=1;j<=100;j++) 6 C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD; 7 }
1 C[0][0]=1; 2 for(int i=1;i<10010;i++) 3 for(int j=0;j<=100;j++) 4 if(j==0) C[i][j]=C[i-1][j]; 5 else C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;
其中第一个是刘汝佳上面的代码,不知为什么在杭电OJ上就是WA,第二个就能AC,就路过的大神指点
题目大意
给你一些不同颜色的石头,问选出一些石头排成一排总共有多少种不同排法,不同数量的石头视为不同情况,每个位置上的石头颜色都相同视为相同情况。
分析
dp+排列组合
dp[i][j] 表示前i堆石子构成长度为j的串的方案数;
状态转移方程是:k为i堆使用的数量
dp[i][j] = (dp[i][j] + dp[i-1][j-k] * C[j][k]%MOD)%MOD;
可以这样想
dp[ i ][ j ] = dp[ i-1 ][ j ]; //未放入第i种颜色的石头
dp[ i ][ j ] += dp[ i-1 ][ j - k ] * C[ j ][ k ]; //放入k个第i种颜色的石
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #define MOD 1000000007 5 using namespace std; 6 typedef long long LL; 7 LL C[10010][110]; 8 void get_c() 9 { 10 memset(C,0,sizeof(C)); 11 for(int i=0;i<10010;i++) 12 { 13 C[i][0]=1; 14 for(int j=1;j<=100;j++) 15 C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD; 16 }//这一步是错的,不知为啥 17 18 19 C[0][0]=1; 20 for(int i=1;i<10010;i++) 21 for(int j=0;j<=100;j++) 22 if(j==0) C[i][j]=C[i-1][j]; 23 else C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD; 24 } 25 LL dp[110][10010]; 26 int main() 27 { 28 int cas=0,sum,n,num; 29 LL ans; 30 get_c(); 31 while(scanf("%d",&n)!=EOF) 32 { 33 memset(dp,0,sizeof(dp)); 34 dp[0][0]=1; 35 sum=0; 36 for(int i=1;i<=n;i++) 37 { 38 scanf("%d",&num); 39 sum+=num; 40 for(int k=0;k<=num;k++) 41 { 42 for(int j=k;j<=sum;j++) 43 dp[i][j]=(dp[i][j]+(dp[i-1][j-k]*C[j][k])%MOD)%MOD; 44 } 45 } 46 ans=0; 47 for(int i=1;i<=sum;i++) 48 ans=(ans+dp[n][i])%MOD; 49 printf("Case %d: %I64d\n",++cas,ans); 50 } 51 return 0; 52 }