這是一種通過建構函式 \(g(x)\) 來求一類積性函式字首和的做法,方法比較精妙
考慮我們要求函式 \(f\) 的字首和 \(s(n) = \sum_^n f(i)\) ,已經有構造好的積性函式 \(g\) 。
將 \(f, g\) 做狄利克雷卷積,此時推式子可以得到:
\[ \sum_^n(f*g)(k) = \sum_^n\sum_ f(d)g(\frac) \\ = \sum_^n g(d)\sum_^\rfloor} f(k) \\ = \sum_^n g(d)s(\lfloor\frac\rfloor) \]
進一步觀察發現:
\[ s(n) =\sum_^n(f*g)(k) - \sum_^n g(d)s(\lfloor\frac\rfloor) \]
對於前面部分要求快速\(o(1)\)得到 \((f*g)\) 的字首和。
對於後面部分需要計算的 \(s(\lfloor\frac\rfloor)\) 不超過 \(2\sqrt\) 個,套用除數函式的那個證明即可。
先套用主定理再積分一下會發現這樣做的複雜度是 \(o(n^})\) 的,如果能線性預處理出前 \(n^}\) 項的 \(s\) ,那麼複雜度就是 \(o(n^})\) 。
對於尤拉函式 \(\phi\) 求字首和 \(s(n) = \sum_^n \phi(i)\) ,以及莫比烏斯函式 \(\mu\) 求字首和,\(s(n) = \sum_^n \mu(i)\) 均可以用恒等函式 \(i(n)=1\) 來做 \(g\)。
因為可以證明得到以下等式:
\[ \phi * 1 = id \\ \mu * 1 = e=[n=1] \]
這兩者的字首和都可以 \(o(1)\) 計算。
code
/*program by mangoyang*/
#include#define inf (0x7f7f7f7f)
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template inline void read(t &x)
const int lim = 10000005;
mapansmiu;
mapansphi;
ll sphi[lim];
int prime[lim], smiu[lim], tot, m;
inline int getmiu(int n)
return ansmiu[n] = ans;
}inline ll getphi(int n)
return ansphi[n] = ans;
}signed main()
sphi[i*prime[j]] = sphi[i] * (prime[j] - 1);
smiu[i*prime[j]] = -smiu[i];}}
for(int i = 2; i < lim; i++)
sphi[i] += sphi[i-1], smiu[i] += smiu[i-1];
read(m);
for(int i = 1, x; i <= m; i++)
read(x), cout << getphi(x) << " " << getmiu(x) << endl;
return 0;
}
學習筆記 杜教篩
入門好部落格 杜教篩 pengym 求一些方便構造卷積形式的積性函式的字首和 不是積性函式如果可以變成卷積形式也可以做 構造h f g,然後推h的字首和,就可以把f字首和遞迴處理 所以,h,g字首和必須可以快速求 有時候,杜教篩的思想也值得借鑑。也是一些題目的解決方法。由於可以記憶化,所以在多次詢問...
學習筆記 杜教篩
dirichlet 卷積,數論分塊 杜教篩用於解決數論函式 f n 的字首和問題,即求 s n sum f i 對於任意數論函式 g n 都有 sum sum f d g left frac right sum g i s left left lfloor frac right rfloor rig...
杜教篩學習筆記
設有四個數論函式 bf h,f,g,s 滿足 mathbf h mathbf f mathbf g mathbf s n sum limits n mathbf f i sum limits n mathbf h i sum limits n sum limits mathbf g d mathbf...