for my darling
题意:有N种石头,每种石头有A1,A2....AN个,现取出一些石头组成序列,求可以组成多少种序列
例如:3种:可以产生:B; G; M; BG; BM; GM; GB; MB; MG; BGM; BMG; GBM; GMB; MBG; MGB.
我们采用动态规划的思想,划分阶段:按照石头种类划分阶段。于是乎,咱们对于第i种石头,相当于之前石头的颜色并不重要,借助高中数学插板法的思想,假如之前的i - 1 种石头,拼出了长度为len,那么,相当于有len + 1个空,咱们要放第 i 种石头进去,于是乎,转化成了经典问题,我比较得意的总结:
球和球 | 盒和盒 | 空盒 | 情况数 |
有区别 | 有区别 | 有空盒 | m^n |
有区别 | 有区别 | 无空盒 | M!s(n,m) |
有区别 | 无区别 | 有空盒 | S(n,1)+s(n,2)+…+s(n,m),n>=m |
S(n,1)+s(n,2)+…+s(n,n),n<=m | |||
有区别 | 无区别 | 无空盒 | S(n,m) |
无区别 | 有区别 | 有空盒 | C(n+m-1,n) |
无区别 | 有区别 | 无空盒 | C(n-1,m-1) |
无区别 | 无区别 | 有空盒 | DP |
无区别 | 无区别 | 无空盒 | DP |
这里,第 i 种石头互相没有区别,len + 1个空有序,相当于有区别,可以有空盒,于是,如果咱们从第 i 种中放put个进去,情况数应该是 C(put + len , put)
于是设计状态:DP[i][j] 表示 用前 i 种石头,排出长度为 j 的可能数
然后,状态转移的时候,枚举在阶段 i 放入put个,DP[i + 1][j + put] += DP[i][j] * C(put + j, put) 即可
复杂度 10000 ^ 2,能过……
写时候时间较紧,外加好久没刷HDU了……出现 1:忘记判EOF 2:长度为len,有len + 1个空,忘记 + 1了……于是一直没过……
1 #include <cstdio> 2 #include <cstring> 3 4 typedef long long Long; 5 6 const int MOD = 1000000007; 7 8 int C[11111][111]; 9 10 void init() { 11 C[0][0] = C[1][0] = C[1][1] = 1; 12 for (int i = 2; i <= 10101; i++) { 13 for (int j = 0; j <= i && j <= 100; j++) { 14 if (j == 0) C[i][j] = 1; 15 else C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MOD; 16 } 17 } 18 } 19 20 21 int dp[111][11111]; 22 int a[111]; 23 24 int main() { 25 init(); 26 for (int ii = 1;;ii++) { 27 int n; if (scanf("%d",&n) == -1) break; 28 memset(dp,0,sizeof(dp)); 29 memset(a,0,sizeof(a)); 30 for (int i = 0; i < n; i++) { 31 scanf("%d",a + i); 32 } 33 for (int i = 0; i <= a[0]; i++) dp[0][i] = 1; 34 int maxlen = a[0]; 35 for (int now = 0; now < n - 1; now ++) { 36 int next = now + 1; 37 for (int len = 0; len <= maxlen; len++) { 38 if (dp[now][len] == 0) continue; 39 dp[next][len] += dp[now][len]; 40 if (dp[next][len] >= MOD) dp[next][len] -= MOD; 41 Long tmp = dp[now][len]; 42 for (int put = 1; put <= a[next]; put++) { 43 Long tt = tmp * C[len + put][put] % MOD; 44 dp[next][len + put] += tt; 45 if (dp[next][len + put] >= MOD) dp[next][len + put] -= MOD; 46 } 47 } 48 maxlen += a[next]; 49 } 50 int ans = 0; 51 for (int i = 1; i <= maxlen; i++) ans = (ans + dp[n - 1][i]) % MOD; 52 printf("Case %d: %d\n",ii,ans); 53 } 54 return 0; 55 }