: Beautiful Numbers ★★★★☆ 題組: Problem Set Archive with Online Judge 題號: 11472: Beautiful Numbers 解題者:邱經達 解題日期: 2011 年 5 月 5 日 題意: 若一個 N 進位的數用到該 base 裡全部的數 字,且任兩個數字之間的差值都剛好是 1 且首位 數字不為 0 ,則該數字為 Beautiful Number 。 給定兩數 N 、 M ,分別代表 N-base 及 M 位數字, 求出在 N-base 中的數字從長度 1 到長度 M 總共出現 多少個 Beautiful Numbers 。 2<=N<=10 , 1<=M<=100 。
2 題意範例: N=2 , M=5 Beautiful Number 一共有以下 4 種 10,101,1010,10101 Output 4 N=3 , M=5 Beautiful Number 一共有以下 9 種 210, 1012,1210,2101, 10121,12101,21010,21012,21210 Output 9
3 解法: Dynamic Programming + Bitmask 使用一 3 維陣列紀錄每個 Number 的狀態及個數 BN[used_digit][length][last_digit] use_digit: 這個 Number 有用到的數字 ( 以二進位表示 ) length: 該 Number 的位元長度 last_digit: 該 Number 的最後一位數字 例: BN[ ][6][2] 可代表 、 、 … 等
4 解法: 若輸入 N=5 M=10 則答案應該會存在以下幾格 BN[ ][length][0] BN[ ][length][1] BN[ ][length][2]... BN[ ][length][9] 其中 length = 1~M ↑ 從第 1 位開始連續五個 1 也就是都使用了 五個數字,長度為 length 而最後一 位數字分別從 0~9 如何計算上面那幾格的答案 ?
5 解法: 從個位數開始向後補位,規則為補上的數要與前一位相差 1 所以以下這些數都可能在補上一些尾數之後形成 beautiful numbers 且 * 只有 * 以下這些數才能以上述的補位規則形成 beautiful numbers 長度 BN[0111][5][1]= BN[1110][5][3]= … BN[0111][5][0]=2 BN[0111][5][2]=1 … 為 base-3 的 beautiful numbers)
6 解法範例: 由於要從個位數開始向後補位,所以初始條件則 令所有表示個位數 (0 除外 ) 的陣列值為 1 BN[used_digit][length][last_digit] BN[ ][1][1] = 1; BN[ ][1][2] = 1; BN[ ][1][3] = 1;... BN[ ][1][9] = 1;
7 解法範例: 則我們可以從上列中的個位數產生長度為 2 的 Numbers ,以個位數字 2 為例: 2→21 ( 補 1) 2→23 ( 補 3) 對以上的動作而言程式應該執行以下的動作 BN[ ][2][1] += BN[ ][1][2]; BN[ ][2][3] += BN[ ][1][2]; 再用長度為 2 的 Numbers 產生長度為 3 的 Numbers 21→210 ( 補 0) 21→212 ( 補 2) 對以上的動作而言程式應該執行以下的動作 BN[ ][3][0] += BN[ ][2][1]; BN[ ][3][2] += BN[ ][2][1];
8 解法範例: 從上列的範例可以觀察出 DP function 為 if (ld-1>=0) : BN[ used_bits | bit(ld-1) ][len+1][ld-1] += BN[used_bits][len][ld]; if (ld+1<10) : BN[ used_bits | bit(ld+1) ][len+1][ld+1] += BN[used_bits][len][ld]; 例: bit(3) =
9 解法範例: 用三層迴圈填完上頁的全部 BN[x][y][z] 陣列表格, x 最外層而 z 最內層, y = 1~100 、 z = 0~9 其中 x 不需要從 ~ 每個值 (1024 個 ) 都跑一遍。 從 Page.5 中的表可以知道,只有 used_bit 表示成 n 個 1 相鄰的數才有可 能向後補位形成 Beautiful Numbers ,也就是若 x 代表的 used_bits 不為 以下這些數值, BN 值必為 0 ,毋需處理 連續一個 1 連續兩個 1 連續三個 ……… … 等
10 解法範例: 利用一陣列 b[55] 依序存放上頁中所有的 x 值,計算方法如下: 連續一個 1 ,從 b[0]~b[9] 共十個 // i = 1~9 b[0] = 1; // b[i] = b[i-1]*2; 連續兩個 1 ,從 b[10]~b[18] 共九個 // i = 11~18 b[10] = 3; // b[i] = b[i-1]*2; 連續三個 1 ,從 b[19]~b[26] 共八個 // i = 20~26 b[19] = 3; // b[i] = b[i-1]*2; 以此類推直到連續十個 1 ,一共 55 個數
11 解法範例: 因此填表可以改寫成 BN[ b[x] ][y][z] , 其中 x = 0 ~ 54 、 y = 1~100 、 z = 0~9 最後對輸入 N 、 M ,問題的答案為: BN[ Beautiful_Numbers_bit[N] ][m][ld] 陣列中 m = 2 ~ M 、 ld = 0 ~ 9 的所有數值之總和
12 解法範例: 其中 Beautiful_Numbers_bit[N] 為 N=2→ N=3→ N=4→ N=5→ N=6→ N=7→ N=8→ N=9→ N=10→
13 討論: 時間複雜度: 需要花費最多時間的地方為填滿 BN[ b[x] ][y][z] O(x*y*z) , x = 0 ~ 54 、 y = 1~100 、 z = 0~9