【模板】Dirichlet 前綴和
求
\[B[i] = \sum_{d|i} A[d] \]
$ n \le 2\times 10^{7} $
看代碼:
for( int i = 1 ; i <= en && pri[i] <= n ; ++ i ) {
for (int j = 1; j * pri[i] <= n; ++j) {
B[j * pri[i]] += B[j];
}
}
為啥這么做它是對的呢?發現每個數字會被它除以所有質因子轉移到,並且是按照質因子從小到大來的。
所以這個代碼相當於,對所有質因子遞歸求,然后對對所有質因子搞前綴和。
形式和 埃篩 一樣,復雜度也是 $ O(n\log\log n) $
然后考慮這個
\[B[i] = \sum_{i|d} A[d] \]
看代碼:
for( int i = 1 ; i <= en && pri[i] <= n ; ++ i ) {
for (int j = n / pri[i]; j; --j) {
B[j] += B[j * pri[i]];
}
}
首先,我們發現最主要的區別在於,我們應當從 一個數字本身 轉移到 這個數字除以所有質因子。因為是從大到小轉移的,所以也需要逆序枚舉 $ j $ 。
最后考慮這個:
\[A[i] = \sum_{d|i} B[d] \]
也是已知 $ A $ 求 $ B $
這種情況其實就是第一種情況反過來,我們也可以直接把循環順序和轉移方法給反過來
for( int i = en ; i ; -- i ) {
for (int j = n / pri[i]; j ; -- j) {
B[j * pri[i]] -= B[j];
}
}
第二種情況也可以反過來,就不贅述了。
例題:CF585E