P4213
Attention
本题极度卡常,不需要long long的情况下尽量使用int,mu函数不需要使用long long。
杜教筛用于求积性函数前缀和。
例如:求 ∑ i = 1 n m u [ i ] \sum_{i=1}^{n} mu[i] ∑i=1nmu[i] 或者 ∑ i = 1 n p h i [ i ] \sum_{i=1}^{n} phi[i] ∑i=1nphi[i]
杜教筛公式:求 S ( n ) = ∑ i = 1 n f ( i ) S(n) = \sum_{i=1}^{n} f(i) S(n)=∑i=1nf(i)
取
g
(
i
)
g(i)
g(i) 为一个积性函数,常见可用积性函数有:
ϕ
(
n
)
\phi(n)
ϕ(n) (欧拉函数,不大于n且与n互质的数的个数)
μ
(
n
)
\mu(n)
μ(n) (莫比乌斯函数)
d
(
n
)
d(n)
d(n) (约数个数,
d
(
n
)
=
∑
i
∣
n
1
d(n) = \sum_{i|n} 1
d(n)=∑i∣n1)
σ
(
n
)
\sigma(n)
σ(n) (约数和函数,
σ
(
n
)
=
∑
i
∣
n
i
\sigma(n) = \sum_{i|n} i
σ(n)=∑i∣ni)
一些完全积性函数,在使用的时候更方便简单:
e
(
n
)
=
[
n
=
=
1
]
e(n) = [n==1]
e(n)=[n==1]
I
(
n
)
=
1
I(n) = 1
I(n)=1
i
d
(
n
)
=
n
id(n) = n
id(n)=n
然后杜教筛就要来啦!
对于两个积性函数
f
f
f,
g
g
g,有
∑
i
=
1
n
(
f
∗
g
)
(
i
)
=
∑
i
=
1
n
∑
x
y
=
i
f
(
x
)
g
(
y
)
=
∑
y
=
1
n
g
(
y
)
∑
x
y
<
=
n
f
(
x
)
=
∑
y
=
1
n
g
(
y
)
S
(
⌊
n
y
⌋
)
\sum_{i=1}^{n} (f*g)(i) = \sum_{i=1}^{n} \sum_{xy=i} f(x)g(y) = \sum_{y=1}^{n} g(y) \sum_{xy<=n} f(x) = \sum_{y=1}^{n}g(y)S(\lfloor \frac{n}{y} \rfloor)
∑i=1n(f∗g)(i)=∑i=1n∑xy=if(x)g(y)=∑y=1ng(y)∑xy<=nf(x)=∑y=1ng(y)S(⌊yn⌋)
将上式变形之后可以发现:
g
(
1
)
S
(
n
)
=
∑
i
=
1
n
(
f
∗
g
)
(
i
)
−
∑
y
=
2
n
g
(
y
)
S
(
⌊
n
y
⌋
)
g(1)S(n) = \sum_{i=1}^{n} (f*g)(i) - \sum_{y=2}^{n}g(y)S(\lfloor \frac{n}{y}\rfloor)
g(1)S(n)=∑i=1n(f∗g)(i)−∑y=2ng(y)S(⌊yn⌋)
至于是怎么变形的大家应该看得懂的。
如果我们可以用一个g把
∑
i
=
1
n
(
f
∗
g
)
(
i
)
\sum_{i=1}^{n}(f*g)(i)
∑i=1n(f∗g)(i)给搞出来,那么我们就可以算出来S(n)了。
使用数论分块还可以把上式后面的复杂度给降到O(
n
\sqrt n
n)
现在我们已经对杜教筛有一个基本的了解了。
然后看一下模板题怎么做。
题目要求
∑
i
=
1
n
ϕ
(
i
)
\sum_{i=1}^{n} \phi(i)
∑i=1nϕ(i) 和
∑
i
=
1
n
μ
(
i
)
\sum_{i=1}^{n} \mu(i)
∑i=1nμ(i)
取
g
(
i
)
=
I
g(i) = I
g(i)=I,那么
ϕ
(
i
)
∗
I
=
i
d
(
i
)
\phi(i) * I = id(i)
ϕ(i)∗I=id(i),
μ
(
i
)
∗
I
=
ϵ
\mu(i) * I = \epsilon
μ(i)∗I=ϵ
其中
ϵ
\epsilon
ϵ的前缀和为1,
i
d
(
i
)
id(i)
id(i)的前缀和为 n*(n+1)/2
且
∑
i
=
a
b
g
(
i
)
=
(
b
−
(
a
−
1
)
)
\sum_{i=a}^{b} g(i) = (b-(a-1))
∑i=abg(i)=(b−(a−1))
首先用线性筛预处理出大概5e6的mu和phi的前缀和,不够的用杜教筛慢慢算就好了。
详细的看代码吧:
/*
杜教筛模板
求phi(i)和mu(i)的前缀和
有 E = [n=1], I(n) = 1, id(n) = n
由于mu * I = E
令f = mu, g = I, (f*g) = E
故 g(1)*Smu(n) = sigma(E) - sigma(g(i)*S(n/i)) (2<=i<=n)
令f = phi, g = I, (f*g) = id
故 g(1)*Sphi(n) = sigma(id(i)) [(1<=i<=n)] - sigma(g(i)*S(n/i)) (2<=i<=n)
复杂度 O(2e9能过)
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5e6+7;
int mu[maxn],pri[maxn];
bool npri[maxn];
ll phi[maxn];
unordered_map<int,int> summu;
unordered_map<int,ll> sumphi;
inline void init()
{
npri[0] = npri[1] = 1;
mu[1] = phi[1] = 1;
for(int i=2;i<maxn;i++)
{
if(!npri[i]) pri[++pri[0]] = i,mu[i] = -1,phi[i] = i-1;
for(int j=1;j<=pri[0] && i*pri[j]<maxn;j++)
{
npri[i*pri[j]] = 1;
if(i%pri[j])
{
mu[i*pri[j]] = -mu[i];
phi[i*pri[j]] = phi[i]*phi[pri[j]];
}
else
{
mu[i*pri[j]] = 0;
phi[i*pri[j]] = phi[i]*pri[j];
break;
}
}
}
for(int i=1;i<maxn;i++) mu[i] += mu[i-1],phi[i] += phi[i-1];
}
inline int gsum(int x) // g(i)的前缀和
{
return x;
}
inline int getsmu(int x)
{
if(x<maxn) return mu[x];
if(summu[x]) return summu[x];
int ans = 1;
for(int l=2,r;l<=x;l=r+1)
{
r = x/(x/l);
ans -= (gsum(r)-gsum(l-1))*getsmu(x/l);
}
return summu[x] = ans/gsum(1);
}
inline ll getsphi(int x)
{
if(x<maxn) return phi[x];
if(sumphi[x]) return sumphi[x];
ll ans = 1LL*x*(x+1)/2;
for(int l=2,r;l<=x;l=r+1)
{
r = x/(x/l);
ans -= (gsum(r)-gsum(l-1))*getsphi(x/l);
}
return sumphi[x] = ans/gsum(1);
}
int main()
{
init();
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
printf("%lld %d\n",getsphi(n),getsmu(n));
}
return 0;
}