在C++中,除了使用<cmath>
中的log
或log2
函數求對數,也可以通過遞推求出所有可能用到的?log?2i?,i∈[1,n]\lfloor \log_2i\rfloor, i\in[1, n]?log2?i?,i∈[1,n]
證明:?log?2i?=?log?2?i2??+1\lfloor \log_2i \rfloor=\lfloor \log_2 \lfloor \frac{i}{2} \rfloor \rfloor+1?log2?i?=?log2??2i???+1
由于log?2i=log?2(i2?2)=log?2i2+log?22=log?2i2+1\log_2i=\log_2(\frac{i}{2}\cdot 2)=\log_2\frac{i}{2}+\log_22=\log_2\frac{i}{2}+1log2?i=log2?(2i??2)=log2?2i?+log2?2=log2?2i?+1
等號兩邊都向下取整,得:
?log?2i?=?log?2i2?+1\lfloor \log_2i \rfloor =\lfloor \log_2\frac{i}{2} \rfloor+1?log2?i?=?log2?2i??+1
- 如果iii是偶數,則i2=?i2?\frac{i}{2}=\lfloor \frac{i}{2} \rfloor2i?=?2i??,因此有
?log?2i?=?log?2i2?+1=?log?2?i2??+1\lfloor \log_2i \rfloor =\lfloor \log_2\frac{i}{2} \rfloor+1 = \lfloor \log_2\lfloor \frac{i}{2} \rfloor \rfloor+1?log2?i?=?log2?2i??+1=?log2??2i???+1 - 如果iii是奇數,則i?12=?i2?\frac{i-1}{2}=\lfloor \frac{i}{2} \rfloor2i?1?=?2i??
設?log?2i?12?=x\lfloor \log_2\frac{i-1}{2} \rfloor =x?log2?2i?1??=x
那么x≤log?2i?12<x+1x\le \log_2\frac{i-1}{2}<x+1x≤log2?2i?1?<x+1
2x≤i?12<2x+12^x\le \frac{i-1}{2}<2^{x+1}2x≤2i?1?<2x+1
由于i?12\frac{i-1}{2}2i?1?是整數,2x+12^{x+1}2x+1也是整數,較小的整數加上12\frac{1}{2}21?后,一定小于較大的整數。
因此有2x≤i?12<i?12+12=i2<2x+12^x\le \frac{i-1}{2}<\frac{i-1}{2}+\frac{1}{2}=\frac{i}{2}<2^{x+1}2x≤2i?1?<2i?1?+21?=2i?<2x+1
所以x≤log?2i2<x+1x\le \log_2{\frac{i}{2}}<x+1x≤log2?2i?<x+1
因此?log?2i2?=x=?log?2i?12?=?log?2?i2??\lfloor \log_2{\frac{i}{2}} \rfloor =x= \lfloor \log_2\frac{i-1}{2} \rfloor= \lfloor \log_2\lfloor \frac{i}{2}\rfloor \rfloor?log2?2i??=x=?log2?2i?1??=?log2??2i???
因此?log?2i?=?log?2i2?+1=?log?2?i2??+1\lfloor \log_2i \rfloor =\lfloor \log_2\frac{i}{2} \rfloor+1 = \lfloor \log_2\lfloor \frac{i}{2} \rfloor \rfloor+1?log2?i?=?log2?2i??+1=?log2??2i???+1
證畢。
已知?log?21?=0\lfloor \log_21 \rfloor=0?log2?1?=0,結合遞推式?log?2i?=?log?2?i2??+1\lfloor \log_2i \rfloor=\lfloor \log_2 \lfloor \frac{i}{2} \rfloor \rfloor+1?log2?i?=?log2??2i???+1即可遞推得到所有可能用到的?log?2i?,i∈[1,n]\lfloor \log_2i\rfloor, i\in[1, n]?log2?i?,i∈[1,n]。
代碼如下:
const int N = 1000005;//N設為n可能達到的最大值
int lg[N];//lg[i]:floor(log_2{i})
void initLg(int n)//生成lg[1]~lg[n]
{//全局變量初值為0,已經設好lg[1] = 0for(int i = 2; i <= n; ++i)lg[i] = lg[i/2]+1;
}
預處理lg數組的時間復雜度為O(n)O(n)O(n)