一開始用 bits reverse 建表 + bits count 建表改良很久,n 極限大概只能到撐到 10^8 左右
改成研究公式解,但不怎麼容易,要解大量的遞迴關係式,計算幾乎靠 Maplesoft 了
時間、空間複雜度皆為 O(log N)
主要解出 2 個公式如下圖,整理後其實還蠻短的:
假設函數 F(N) 為此題解,
則
式 (1):X( floor(log2(N)) ) = F(2^s - 1),s 為最大的整數滿足 N > 2^s - 1,也就是 sum { f( i + reverse(i)) | i >= 1 且 i 的二進位表示法的長度 < N 的二進位表示法的長度 }
式 (2):Y(i,j) 為將區間 [2^s, 2^(s+1)] 分成 2^(i+1) 等分,第 2 * j + 1 區間的總合, 每一組 i,j 可以決定一組 a,c,d,e,f,g,h,m
至於i,j 與 a,c,d,e,f,g,h,m 的關係可以,先寫個簡單的暴力解程式,列出 N <= 2^26 的解,觀察 式(1)及式(2)的 等差/等比 係數得到
ex: N = 45
解可折成 (1) 式 + { (2)式 } 二分法總合 = [1,31) + { [32,40) + [40, 44) + 45 }
P.S. 式(1)如果在 c 用pow() 函數,如果沒整理好,或是從 double 轉成 long的時機不對,在 N=10^15 時會誤差 1,因此吃了個NA,
如果改用位移 N < 8 時也會有問題,又吃個 NA,沒想到一式通用的方法,最後只好用 if-else 分兩段
參考
反轉 bit
https://stackoverflow.com/questions/746171/most-efficient-algorithm-for-bit-reversal-from-msb-lsb-to-lsb-msb-in-c/16994674
計算二進位中 1 的個數
https://en.wikipedia.org/wiki/Hamming_weight