[SOJ #112]Dirichlet 前缀和
题目大意:给定一个长度为$n$的序列$a_n$,需要求出一个序列$b_n$,满足:
$$
b_k=\sum\limits_{i|k}a_i
$$
$n\leqslant10^7$
题解:$\mathrm{Dirichlet}$前缀和,考虑把$k$写成一个无穷向量$[\beta_1,\beta_2,\beta_3,\cdots]$,满足$k=\sum\limits_iP_i^{\beta_i}$,$P_i$为第$i$个质数。相同的,把$i$写成$[\alpha_1,\alpha_2,\alpha_3,\cdots]$,于是:
$$
\begin{align*}
b_{\beta_{k,1},\beta_{k,2},\beta_{k,2},\cdots}&=\sum\limits_{i|k}a_{\alpha_{i,1},\alpha_{i,2},\alpha_{i,3},\cdots}\\
&=\sum\limits_{\forall\beta_{k,j}\geqslant\alpha_{i,j}}a_{\alpha_{i,1},\alpha_{i,2},\alpha_{i,3},\cdots}
\end{align*}
$$
于是先线性筛出质数,再做一个高维前缀和即可。复杂度$O(n\log\log n)$
卡点:无
C++ Code:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> const int maxn = 1e7 + 5; typedef unsigned int uint; typedef unsigned long long ull; struct random { ull seed; static const ull multiplier = 0x5deece66dll; static const ull addend = 0xbll; static const ull mask = 0xffffffffffffll; void set_seed (ull _seed) {seed = _seed;} uint next() { seed = (seed * multiplier + addend) & mask; return seed >> 16; } } rnd; int plist[maxn >> 3], ptot; bool notp[maxn]; void sieve(const int n) { for (int i = 2; i <= n; ++i) { if (!notp[i]) plist[ptot++] = i; for (int j = 0, t; (t = i * plist[j]) <= n; ++j) { notp[t] = 1; if (i % plist[j] == 0) break; } } } int n; uint s[maxn]; int main() { std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0); std::cin >> n >> rnd.seed; for (int i = 1; i <= n; ++i) s[i] = rnd.next(); sieve(n); for (int i = 0; i < ptot; ++i) { const int P = plist[i]; for (int j = 1, t; (t = j * P) <= n; ++j) s[t] += s[j]; } uint ans = 0; for (int i = 1; i <= n; ++i) ans ^= s[i]; std::cout << ans << '\n'; return 0; }