题目
求 ∑ i = 1 n ∑ j = 1 n φ ( g c d ( i , j ) ) \sum_{i=1}^n\sum_{j=1}^n\varphi(gcd(i,j)) i=1∑nj=1∑nφ(gcd(i,j))
分析
=
∑
d
=
1
n
φ
(
d
)
∑
i
=
1
⌊
n
d
⌋
∑
j
=
1
⌊
n
d
⌋
[
g
c
d
(
i
,
j
)
=
=
1
]
=\sum_{d=1}^n\varphi(d)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{d}\rfloor}[gcd(i,j)==1]
=d=1∑nφ(d)i=1∑⌊dn⌋j=1∑⌊dn⌋[gcd(i,j)==1]
=
∑
d
=
1
n
φ
(
d
)
∑
i
=
1
⌊
n
d
⌋
∑
j
=
1
⌊
n
d
⌋
∑
k
∣
i
,
k
∣
j
μ
(
k
)
=\sum_{d=1}^n\varphi(d)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{k|i,k|j}\mu(k)
=d=1∑nφ(d)i=1∑⌊dn⌋j=1∑⌊dn⌋k∣i,k∣j∑μ(k)
=
∑
d
=
1
n
φ
(
d
)
∑
k
=
1
⌊
n
d
⌋
μ
(
k
)
(
⌊
n
k
d
⌋
)
2
=\sum_{d=1}^n\varphi(d)\sum_{k=1}^{\lfloor\frac{n}{d}\rfloor}\mu(k)(\lfloor\frac{n}{kd}\rfloor)^2
=d=1∑nφ(d)k=1∑⌊dn⌋μ(k)(⌊kdn⌋)2
枚举
i
=
k
d
i=kd
i=kd可以得到
=
∑
i
=
1
n
(
⌊
n
i
⌋
)
2
∑
d
∣
i
μ
(
d
)
φ
(
i
d
)
=\sum_{i=1}^n(\lfloor\frac{n}{i}\rfloor)^2\sum_{d|i}\mu(d)\varphi(\frac{i}{d})
=i=1∑n(⌊in⌋)2d∣i∑μ(d)φ(di)
后面预处理,详见代码,时间复杂度
O
(
N
+
T
(
n
)
)
O(N+T\sqrt(n))
O(N+T(n))
代码
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=1e7+1; bool v[N];
int prime[N],cnt; long long dp[N];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(long long ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline void init(){
dp[1]=1;
for (rr int i=2;i<N;++i){
if (!v[i]) prime[++cnt]=i,dp[i]=i-2;
for (rr int j=1;j<=cnt&&prime[j]*i<N;++j){
v[i*prime[j]]=1;
if (i%prime[j]==0){
if (i/prime[j]%prime[j]==0) dp[i*prime[j]]=dp[i]*prime[j];//dp[i*prime[j]]含有指数超过2次的prime[j],所以不含或含1次prime[j]的莫比乌斯函数会被消掉,所以剩下的就是超过1次的欧拉函数,按照欧拉函数的方法是乘上prime[j]
else dp[i*prime[j]]=dp[i/prime[j]]*(prime[j]-1)*(prime[j]-1);//脑补一下
break;
}
dp[i*prime[j]]=dp[i]*dp[prime[j]];//狄利克雷卷积也是积性函数
}
}
for (rr int i=2;i<N;++i) dp[i]+=dp[i-1];
}
signed main(){
init();
for (rr int t=iut();t;--t){
rr int n=iut(); rr long long ans=0;
for (rr int l=1,r;l<=n;l=r+1)
ans+=(dp[r=n/(n/l)]-dp[l-1])*(n/l)*(n/l);
print(ans),putchar(10);
}
return 0;
}
分析
然而此代码跑的很慢,然而如果推广到
n
n
n和
m
m
m就很实用,以下方法就废掉了,不过上面的好像也会废掉
=
∑
d
=
1
n
φ
(
d
)
∑
i
=
1
⌊
n
d
⌋
∑
j
=
1
⌊
n
d
⌋
[
g
c
d
(
i
,
j
)
=
=
1
]
=\sum_{d=1}^n\varphi(d)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{d}\rfloor}[gcd(i,j)==1]
=d=1∑nφ(d)i=1∑⌊dn⌋j=1∑⌊dn⌋[gcd(i,j)==1]
其实这里就可以直接出结果了,根据洛谷 2158 仪仗队,可以知道答案是
∑
d
=
1
n
φ
(
d
)
(
2
φ
(
⌊
n
d
⌋
)
−
1
)
\sum_{d=1}^n\varphi(d)(2\varphi(\lfloor\frac{n}{d}\rfloor)-1)
d=1∑nφ(d)(2φ(⌊dn⌋)−1)
时间复杂度相同,实测总时间少了1000ms
代码
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=1e7+1; int prime[N],cnt; long long phi[N];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(long long ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline void init(){
phi[1]=1;
for (rr int i=2;i<N;++i){
if (!phi[i]) prime[++cnt]=i,phi[i]=i-1;
for (rr int j=1;j<=cnt&&prime[j]*i<N;++j){
if (i%prime[j]==0){
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
for (rr int i=2;i<N;++i) phi[i]+=phi[i-1];
}
signed main(){
init();
for (rr int t=iut();t;--t){
rr int n=iut(); rr long long ans=0;
for (rr int l=1,r;l<=n;l=r+1)
ans+=(phi[r=n/(n/l)]-phi[l-1])*((phi[n/l]<<1)-1);
print(ans),putchar(10);
}
return 0;
}