【bzoj4804】欧拉心算

  • 本文为博主原创,未经许可不得转载

首先推一波式子可以得到:

$LHS=\sum_{T=1}^{n}\left\lfloor\frac{n}{T}\right\rfloor\left\lfloor\frac{n}{T}\right\rfloor\sum_{d|T}\mu(d)\phi(\frac{T}{d})$

设$g(T)=\sum_{d|T}\mu(d)\phi(\frac{T}{d})=\mu\times\phi$,所以$g(T)$是积性函数,考虑线筛

(1)$g(1)=\mu(1)\phi(1)=1$

(2)当$i$为质数时,$g(i)=\mu(1)\phi(i)+\mu(i)\phi(1)=i-2$

(3)当$i\%prime[j] \neq 0$时,$g(i\times prime[j])=g(i)\times g(prime[j])$

(4)当$i\%prime[j]=0$时,下面重点讨论(下式中$prime[j]$简写为$p_j$):

设$i=p_j^a \prod p_c^{q_c}$,根据$g(i)$的积性有

$g(i)=g(p_j^a)\prod g(p_c^{q_c})$

$g(i\times p_j)=g(p_j^{a+1})\prod g(p_c^{q_c})$

故有$\frac{g(i\times p_j)}{g(i)}=\frac{g(p_j^{a+1})}{g(p_j^a)}=\frac{\mu(1)\phi(p_j^{a+1})+\mu(p_j)\phi(p_j^a)}{\mu(1)\phi(p_j^{a})+\mu(p_j)\phi(p_j^{a-1})}=\frac{\phi(p_j^{a+1})-\phi(p_j^a)}{\phi(p_j^a)-\phi(p_j^{a-1})}$

①当$a>1$时,$LHS=\frac{p_j^{a+1}\times \frac{p_j-1}{p_j}-p_j^{a}\times \frac{p_j-1}{p_j}}{p_j^{a}\times \frac{p_j-1}{p_j}-p_j^{a-1}\times \frac{p_j-1}{p_j}}=p_j$,即$g(i\times primej)=prime[j]\times g(i)$

②当$a=1$时,$LHS=\frac{\phi(p_j^2)-\phi(p_j)}{\phi(p_j)-\phi(1)}=\frac{(p_j-1)^2}{p_j-2}$

注意到这个式子和①中的不一样,这是因为按照定义式计算欧拉函数值得话$\phi(1)=0$,但实际上$\phi(1)=1$

由于分母变成了$p_j-2$导致$p_j=2$的情况无法处理,我们考虑另一种思路:

显然根据积性有$g(i\times p_j)=g(\frac{i}{p_j})\times g(p_j^2)=g(\frac{i}{p_j})\times (\mu(1)\phi(p_j^2)+\mu(p_j)\phi(p_j))=g(\frac{i}{p_j})\times (p_j-1)^2$

这样就完美解决了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include<bits/stdc++.h>
#define FILE "read"
#define MAXN 10000100
using namespace std;
typedef long long ll;
int cnt,prime[MAXN/10],check[MAXN];ll g[MAXN];
inline int read(){
int x=0,f=1; char ch=getchar();
while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch=getchar();}
while(ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
void Init(){
int N=10000000; g[1]=1;
for(int i=2;i<=N;++i){
if(!check[i]) prime[++cnt]=i,g[i]=i-2;
for(int j=1;j<=cnt&&prime[j]*i<=N;++j){
check[prime[j]*i]=1;
if(i%prime[j]==0){
if((i/prime[j])%prime[j]==0) g[prime[j]*i]=g[i]*prime[j];
else g[prime[j]*i]=g[i/prime[j]]*(prime[j]-1)*(prime[j]-1);
break;
}
else g[prime[j]*i]=g[i]*g[prime[j]];
}
}
for(int i=1;i<=N;++i) g[i]+=g[i-1];
}
void solve(){
int n=read(); ll ans=0;
for(int i=1,last;i<=n;i=last+1){
last=(n/(n/i));
ans+=1LL*(n/i)*(n/i)*(g[last]-g[i-1]);
}
printf("%lld\n",ans);
}
int main(){
freopen(FILE".in","r",stdin);
freopen(FILE".out","w",stdout);
Init(); int T=read(); while(T--) solve();
return 0;
}

  

  

然而看了题解,我才发现我SB了

题上给的两个求和号上界都是$n$不是白给的,按照仪仗队那道题做就行了

$LHS=\sum_{k=1}^{n}\phi(k)\sum_{i=1}^{\left\lfloor\frac{n}{k}\right\rfloor}\sum_{j=1}^{\left\lfloor\frac{n}{k}\right\rfloor}[gcd(i,j)==1]$

$=\sum_{k=1}^{n}\phi(k)[\sum_{i=1}^{\left\lfloor\frac{n}{k}\right\rfloor}2\phi(i)-1]$

$=2\sum_{k=1}^{n}\phi(k)Sum(\left\lfloor\frac{n}{k}\right\rfloor)-sum(n)$(其中$sum$是$\phi$的前缀和)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include<bits/stdc++.h>
#define FILE "read"
#define MAXN 10000010
using namespace std;
typedef long long ll;
int cnt,prime[MAXN/10],check[MAXN];ll phi[MAXN];
inline int read(){
int x=0,f=1; char ch=getchar();
while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch=getchar();}
while(ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
void Init(){
int N=10000000; phi[1]=1;
for(int i=2;i<=N;++i){
if(!check[i]) prime[++cnt]=i,phi[i]=i-1;
for(int j=1;j<=cnt&&prime[j]*i<=N;++j){
check[prime[j]*i]=1;
if(i%prime[j]==0) {phi[prime[j]*i]=phi[i]*prime[j]; break;}
else phi[prime[j]*i]=phi[i]*phi[prime[j]];
}
}
for(int i=1;i<=N;++i) phi[i]+=phi[i-1];
}
void solve(){
int n=read(); ll ans=0;
for(int i=1,last;i<=n;i=last+1){
last=(n/(n/i));
cadd(ans,phi[n/i]*(phi[last]-phi[i-1]);
}
printf("%lld\n",ans*2-phi[n]);
}
int main(){
freopen(FILE".in","r",stdin);
freopen(FILE".out","w",stdout);
Init(); int T=read(); while(T--) solve();
return 0;
}
文章目录
,