P4213 【模板】杜教篩(Sum)
\(\color{#0066ff}{題 目 描 述}\)
給定一個正整數\(N(N\le2^{31}-1)\)
求
\(\begin{aligned} ans_1=\sum_{i=1}^n\varphi(i) \end{aligned}\)
\(\begin{aligned} ans_2=\sum_{i=1}^n \mu(i) \end{aligned}\)
\(\color{#0066ff}{輸 入 格 式}\)
一共T+1行
第1行為資料組數T(T<=10)
第2~T+1行每行一個非負整數N,代表一組詢問
\(\color{ #0066ff }{ 輸 出 格 式 }\)
一共T行,每行兩個用空格分隔的數ans1,ans2
\(\color{#0066ff}{輸入樣例}\)
6
1
2
8
13
30
2333
\(\color{#0066ff}{ 輸 出 樣 例}\)
1 1
2 0
22 -2
58 -3
278 -3
1655470 2
\(\color{#0066ff}{數 據 範 圍 與 提 示}\)
\(N \leq 2^{31}\)
\(\color{#0066ff}{題 解}\)
前置知識1 : 狄利克雷卷積
對於任意函式f,g,有\(\begin{aligned} h(i) = \sum_{d|i}f(d)*g(\frac{n}{d})\end{aligned}\)
h即為f和g的卷積
常用函式
1、\(i(n) = 1\)
2、\(id(n) = n\)
3、\(e(n)=\left\{\begin{aligned}1\ \ \ n = 1 \\ 0 \ \ \ n \neq 1\end{aligned}\right.\)
4、尤拉函式\(\varphi(n)\)
5、懵逼鎢絲函式\(\mu(n)=\left\{\begin{aligned}1\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ n = 1 \\ (-1)^k \ \ \ n由k個不同質數相乘得到\\ 0\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 其它情況\end{aligned}\right.\)
6、\(\sigma(n)=n的約數和\)
7、\(d(n)=n的約數個數\)
常用卷積
1、\(i*\mu = e\)
2、\(e*a=a\)
3、\(\mu * id= \varphi\)
4、\(i*id=\sigma\)
5、\(i*i=d\)
6、\(i*\varphi=id\)
杜教篩
已知\(f(i)\)
用來求\(\begin{aligned}\sum_{i = 1}^n f(i)\end{aligned},n\leq 2^{31}\)
定義\(h(i)=(f*g)(i)=\begin{aligned}\sum_{d|i}f(d)*g(\frac{i}{d})\end{aligned}\)
\(\displaystyle\sum_{i=1}^nh(i)\)
用定義展開
\(=\displaystyle\sum_{i=1}^n\sum_{d|i}g(d)f\left(\frac i d\right)\)
d的範圍也是【1.n】的,所以改成列舉d,找它的倍數,這個式子是在求和,找全了就行
\(=\displaystyle \sum_{d=1}^ng(d)\sum_{d|i}f\left(\frac i d \right)\)
把後面變一下
\(=\displaystyle \sum_{d=1}^ng(d)\sum_{i=1}^{\left\lfloor\frac n d \right \rfloor}f( i)\)
然後
\(=\displaystyle \sum_{i=1}^ng(i)S\left(\left\lfloor\frac n i\right\rfloor\right)\)
所以
\(\displaystyle \sum_{i=1}^nh(i)=\sum_{i=1}^ng(i)S\left(\left\lfloor\frac n i\right\rfloor\right)\)
有一個好像沒用的式子
\(\displaystyle g(1)S(n)=\sum_{i=1}^ng(i)S\left(\left\lfloor\frac n i\right\rfloor\right)-\sum_{i=2}^ng(i)S\left(\left\lfloor\frac n i\right\rfloor\right)\)
上式把後面移項就成恆等式了
我們把右面第一項用剛剛的結論換走
\(\displaystyle g(1)S(n)=\sum_{i=1}^nh(i)-\sum_{i=2}^ng(i)S\left(\left\lfloor\frac n i\right\rfloor\right)\)
這。。是個遞迴式
就沒了
對於S的遞迴,用數列分塊
一般的h和g都很好求(構造)
對於本題來說
\(i*\varphi=id\)
所以對於\(\varphi\)
\(\displaystyle S(n)=\frac{n*(n+1)}{2}-\sum_{i=2}^nS\left(\left\lfloor\frac n i\right\rfloor\right)\)
剛剛有\(i*\mu=e\)
所以
\(\displaystyle S(n)=1-\sum_{i=2}^nS\left(\left\lfloor\frac n i\right\rfloor\right)\)
沒了。。。
把前\(4*10^6\)的東西線性篩一下
最後的複雜度\(O(n^{\frac{2}{3}})\)不會證
#include <bits/stdc++.h>
typedef long long LL;
const int maxn = 4e6;
const int maxx = 4e6 + 10;
int in() {
char ch; int x = 0, f = 1;
while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
return x * f;
}
bool vis[maxx];
LL phi[maxx];
int mu[maxx], pri[maxx], tot;
std::map<int, LL> P;
std::map<int, int> M;
void predoit() {
phi[1] = mu[1] = 1LL;
for(int i = 2; i <= maxn; i++) {
if(!vis[i]) {
pri[++tot] = i;
phi[i] = i - 1;
mu[i] = -1;
}
for(int j = 1; j <= tot && i * pri[j] <= maxn; j++) {
vis[i * pri[j]] = true;
if(i % pri[j] == 0) {
phi[i * pri[j]] = phi[i] * pri[j];
mu[i * pri[j]] = 0;
break;
}
else {
phi[i * pri[j]] = phi[i] * (pri[j] - 1);
mu[i * pri[j]] = -mu[i];
}
}
}
for(int i = 2; i <= maxn; i++) {
phi[i] += phi[i - 1];
mu[i] += mu[i - 1];
}
}
LL workphi(int now)
{
if(now <= maxn) return phi[now];
if(P.count(now)) return P[now];
LL ans = now * (now + 1LL) / 2;
for(int i = 2, lst; i <= now; i = lst + 1) {
lst = now / (now / i);
ans -= 1LL * (lst - i + 1LL) * workphi(now / i);
}
return P[now] = ans;
}
int workmu(int now)
{
if(now <= maxn) return mu[now];
if(M.count(now)) return M[now];
int ans = 1;
for(int i = 2, lst; i <= now; i = lst + 1) {
lst = now / (now / i);
ans -= workmu(now / i) * (lst - i + 1);
}
return M[now] = ans;
}
int main() {
predoit();
for(int T = in(); T --> 0;) {
int n = in();
printf("%lld %d\n", workphi(n), workmu(n));
}
return 0;
}