題目: UVa - 10912 - Simple Minded Hashing 
題目說明 26 個英文字母,依序從 1 開始編號,a = 1, b = 2, …, z = 26。
給兩個整數 L、S,求使用 L 個英文字母,組成編號總和為 S 的嚴格遞增字串的字串個數。
Input:  每組測資有兩個整數,依序為 L、S。若皆為 0 表結束。
Output:  輸出使用 L 個英文字母,組成編號總和為 S 的嚴格遞增字串的字串個數。
解題思路 動態規劃題,由於測資範圍不大,因此先算出所有情況的答案再輸出即可。
由於組成的字串必須是嚴格遞增,因此最多只會有 26 個字母,且編號總和最大為 351 ( 1 + 2 + … + 26 )。
定義 dp[i][j][k] 表只使用前 i 個字母 ( 編號 1 ~ i 的字母 ),組成長度為 j,總和為 k 的字串的所有情況數,先設定初始狀態 dp[n][1][n] = 1,對於所有 1 <= n <= 26 ,因為若只有一個字母,組成與自己編號總和相同的字串,必定就是只有自己一種情況而已。
對於 dp[i][j][k]:
若 k < i,表示 i 無法出現在字串中,則 dp[i][j][k] = max(dp[i - 1][j][k], dp[i][j][k])。 
若 k >= i,表示 i 可以出現在字串中,則 dp[i][j][k] += dp[i - 1][j - 1][k - i],可以理解為若要將 i 放入字串中,可能數為 最大可能字母為 i - 1,長度為 j - 1,總和為 k - i 的字串,因為將 i 接上後會組成 最大可能字母為 i,長度為 j,總和為 k 的字串。 
 
簡單來說,就是不斷枚舉是否能將字母放入最後一位,若無法則至少情況數會是 i - 1 的情況數,這樣才符合最初 dp 數組的定義。
參考解法 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 33 34 35 36 37 38 39 40 41 42 43 #include  <bits/stdc++.h>  using  namespace  std ;static  auto  __ = []{     ios_base::sync_with_stdio(0 );     cin .tie(0 );     cout .tie(0 );     return  0 ; }(); int  Cas;int  L, S;int  dp[27 ][27 ][352 ]; void  compute ()     for  (int  i = 1 ; i <= 26 ; ++i) dp[i][1 ][i] = 1 ;     for  (int  i = 1 ; i <= 26 ; ++i) for  (int  j = 1 ; j <= i; ++j)     {         for  (int  k = 1 ; k <= 351 ; ++k)         {             dp[i][j][k] += dp[i - 1 ][j][k];                          if  (k >= i) dp[i][j][k] += dp[i - 1 ][j - 1 ][k - i];         }     } } int  main ()     compute();     while  (cin  >> L >> S && L && S)     {         cout  << "Case "  << ++Cas << ": " ;                  if  (L > 26  || S > 351 ) cout  << "0\n" ;         else  cout  << dp[26 ][L][S] << '\n' ;     } } 
由於只需要使用 26 個字母的情況,所以可以縮一維。
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 33 34 35 36 37 #include  <bits/stdc++.h>  using  namespace  std ;#define  FOR(i, a, b) for(int i = a; i < b; ++i) static  auto  __ = []{     ios_base::sync_with_stdio(0 );     cin .tie(0 );     cout .tie(0 );     return  0 ; }(); const  int  INF = (int )1e9 ;int  L, S;int  C;int  dp[27 ][352 ];void  compute ()     dp[0 ][0 ] = 1 ;     FOR(i, 1 , 27 ) for  (int  j = 26 ; j > 0 ; --j) FOR(k, i, 352 )         dp[j][k] += dp[j - 1 ][k - i]; } int  main ()     compute();     while  (cin  >> L >> S && (L || S))     {         cout  << "Case "  << ++C << ": " ;         if  (L > 27  || S > 351 ) cout  << "0\n" ;         else  cout  << dp[L][S] << '\n' ;     } } 
參考資料 UVa/10912 - Simple Minded Hashing.cpp at master · morris821028/UVa