最近突然做到一些求積性函式字首和的題,用到了各種篩,有一題用到 min_25 篩法,於是好好學習了一波,運用極不熟練。後來又遇到一道杜教篩的題,結果發現自己連 phi(x) 字首和都不會推了?嚇得我趕緊複習 + 寫部落格。
常見(完全)積性函式;整除分塊; dirichlet 卷積;埃氏篩
這裡還是簡單介紹一下dirichlet 卷積:
我們用 * 表示兩個函式的 dirichlet 卷積。接下來,設 $f$ 為積性函式,我們要求 $\sum_^ f(i)$ , n 是 $10^9\sim 10^$ 左右的級別。本文忽略複雜度分析(需用到積分相關知識,本人太弱不會)。定義函式 f 和 g 的 dirichlet 卷積形式為 $(f*g)(n)=\sum_ f(d)g\left (\frac\right )$ 。
適用範圍:存在另兩個積性函式 $g,h$ ,且滿足 $f*g=h$ , $g,h$ 函式的字首和比較容易求。
先來舉幾個例子:
那麼具體怎麼求呢?
設 $s(n)=\sum_^ f(i)$ ,那麼有
$$\begin \sum_^ (f*g)(i) &= \sum_^ \sum_ f(d)g\left (\frac \right ) \\ s(n)=\sum_^n f(i) &= \sum_^ (f*g)(i) - \sum_^ \sum_$ 的時候複雜度最優,大概為 $\mathcal(n^)$ 。足以解決這個問題。
貼**(一百年前寫的)
1 #include251nod1244 莫比烏斯函式之和#define rep(i,x,y) for (int i=(x);i<=(y);i++)
3#define ll long long
4using
namespace
std;
5const
int n=1e6+5;6
int p[n/10],cnt,vis[n],mu[n]; mapmp;
7void init(int
n)16
}17 rep (i,2,n) mu[i]+=mu[i-1
];18}19
ll s(ll n)
27return mp[n]=ret;28}
29int
main()
一些吐槽:這個杜教篩真的是篩??好吧其實我也不知道它為什麼叫杜教篩,這確實只是個遞迴求和的方法。( yhx : 應該叫杜氏求和法)
不管這些,下面介紹一種真正的篩—— min_25 篩。它本質和洲閣篩相同,但小一倍常數。眾所周知數論題非常容易被卡常數,所以學好 min_25 篩還是很重要的 ~
適用範圍:函式 f 需要滿足 $f(p)$ 是乙個低階多項式, $f(p^c)$ 有較為容易的求法,最好是 $\mathcal(1)$ 。這裡 p 代表任意素數。
首先 min_25 篩和洲閣篩都是基於埃氏篩的。
要求 $\sum_^ f(i)$ ,我們把 $1\sim n$ 中的素數和合數分開考慮。
假設素數集合為 $p$ , $p_i$ 為第 i 個素數, $minp(i)$ 表示 i 的最小素因子。
素數以下假設 $f(p)$ 為完全積性函式(但 $f(i)$ 不一定。原因下面會說)。
要求 $\sum_^n [i \in p]f(i)$ 。
為了方便計算,這裡所有數的函式值都定義為 $f(p)$ ,即都和 $f(p)$ 使用一樣的表示式。
設 $g(n,j)=\sum_^n [i\in p\ or \ minp(i)>p_j]f(i)$ ,即篩到第 j 個素數為止剩下的數和所有素數的函式值之和。
考慮 $g(n,j)$ 的轉移:
那麼 $\sum_^n [i \in p]f(i)=g(n,|p|)$ ,這裡 $p$ 是前 $\sqrt$ 個素數的集合。
【稍微解釋一下這個過程】
由於我們最終用到的函式值只有 $g(n,|p|)$ ,即我們這步求的是素數的函式值,按照我們的篩法,實際上是先將所有數都按照 $f(p)$ 的式子計算函式值,然後把合數篩掉,最後只剩下素數,那麼就能得到正確的函式值之和。但是中間篩的過程中,如果 $f(x)$ 的表示式和 $f(p)$ 不一樣的話, $g$ 的值並不是真實的函式值。所以注意這裡只求出了素數函式值之和。
合數這裡沒有素數那欄裡的若干限制。
設 $s(n,j)=\sum_^n [minp(i)\geq p_j]f(i)$ 。和 $g$ 類似的定義,但注意這裡取到了等號,且不包含素數。
$s$ 的值分 2 部分計算:質數,合數。 1 的函式值放到最後計算。
質數的函式值即 $g(n,|p|)-\sum_^ f(p_i)$ 。至於合數,由於 $f(x)$ 是積性函式,那麼可以把最小質因子全部提出來(它和剩下部分互質),所以列舉它的最小質因子 $p_k$ 及冪次 $e$ ,得 $$s(n,j)=g(n,|p|)-\sum_^f(p_i)+\sum_\sum_^\leq n}(f(p_k^e)s\left (\left \lfloor \frac \right \rfloor,k+1 \right )+f(p_k^))$$
後面的 $f(p_k^)$ 是單獨處理的特殊情況,由於前面無法統計到。
這樣總複雜度為 $\mathcal(\frac})$ 。
【為什麼要求 $f(p)$ 為低階多項式呢】
我們在處理素數部分的時候說過假設 $f(p)$ 為完全積性函式。那麼低階多項式一定能拆成 $\sum_ a_ix^i$ ,這裡每一項都是完全積性的,所以只需拆項使用上述方法求解即可。複雜度 $\times 階數$ 。
栗子loj6053 簡單的函式
這題的函式比較奇怪,但好在它是積性的; $f(p)$ 除 $p=2$ 時均為 $p-1$ ,是乙個低階多項式; $f(p^c)$ 可以 $\mathcal(1)$ 求解。所以可以用 min_25 篩求解。
把 $f(p)$ 拆掉, $p=2$ 的時候特判一下。別的直接套用上面的公式即可。
code:
1 #include2loj6053 - 簡單的函式#define rep(i,x,y) for (int i=(x);i<=(y);i++)
3#define ll long long45
using
namespace
std;67
const
int n=2e5+10,mod=1e9+7
;8 ll n,w[n]; int
m,sq,id1[n],id2[n],h[n],g[n],p[n],cnt,pre[n],vis[n];
910 inline int get_id(ll x)
1112
void sieve(int
n)19}20
}2122int s(ll n,int
i)32
return
res;33}
3435
intmain()
43 rep (j,1
,cnt)
44for (int i=1;i<=m&&(ll)p[j]*p[j]<=w[i];i++)
49 printf("
%d\n
",s(n,1)+1
);50
return0;
51 }
積性函式求字首和
若函式f滿足 a,b互質有f a b f a f b 我們則稱f是積性函式。常見的比如尤拉函式,莫比烏斯函式,都屬於積性函式。線性篩法,利用積性函式的積性,篩素數同時可以計算積性函式。然而有些問題要求低於線性的複雜度。同樣利用積性函式的性質。舉常見的莫比烏斯函式為例。求 ni 1 i 1 n 10 ...
陣列 字首和 字首積及其應用
字首和 字首積也稱字首和陣列,字首積陣列。給一陣列a,字首和 新建一陣列b,陣列中每一項b i 儲存a中 0 i 的和 字尾和 新建一陣列b,陣列中每一項b i 儲存a中 i n 1 的和 字首積 新建一陣列b,陣列中每一項b i 儲存a中 0 i 的積 字尾積 新建一陣列b,陣列中每一項b i 儲...
積性函式求和小記
模板題 p4213 模板 杜教篩 sum ac code 沒開o2優化過了,開了反而沒過,玄學優化233 include include using namespace std using namespace tr1 typedef long long ll const int maxn 5e6 b...