Description

n
,
m
≤
1
e
7
n,m\le1e7
n,m≤1e7
Solution
- 后面那个互质数之和由于对称性可以得到是 ϕ ( n ) n / 2 \phi(n)n/2 ϕ(n)n/2,需要特判 n = 1 n=1 n=1
- 然后把 ϕ ( i j ) \phi(ij) ϕ(ij)拆成 ϕ ( i ) ϕ ( j ) ( i , j ) ϕ ( ( i , j ) ) \phi(i)\phi(j)\frac{(i,j)}{\phi((i,j))} ϕ(i)ϕ(j)ϕ((i,j))(i,j),相当于是一个容斥掉 1 p − 1 \frac{1}{p-1} p−11
- 然后直接枚举 ( i , j ) (i,j) (i,j),由于 n , m ≤ 1 e 7 n,m\le1e7 n,m≤1e7,可以直接高维前缀和、差分求gcd,枚举gcd,求出贡献即可(才不要什么莫比乌斯反演呢,莫比乌斯反演一般做 1 e 9 1e9 1e9级别的整除分块)。
- 高维前缀和时间复杂度与埃氏筛一样。
有关phi的性质
1.
ϕ
=
μ
∗
i
d
\phi=\mu*id
ϕ=μ∗id,证明:
ϕ
(
n
)
=
∑
i
=
1
n
[
(
i
,
n
)
=
1
]
=
∑
d
∣
n
μ
(
d
)
n
d
\phi(n)=\sum_{i=1}^n[(i,n)=1]=\sum_{d|n}\mu(d)\frac{n}{d}
ϕ(n)=∑i=1n[(i,n)=1]=∑d∣nμ(d)dn
2.
∑
i
=
1
n
∑
j
=
1
m
(
i
,
j
)
=
∑
d
=
1
n
d
∑
k
=
1
n
/
d
μ
(
k
)
(
n
/
k
d
)
(
m
/
k
d
)
=
∑
T
=
1
n
ϕ
(
T
)
(
n
/
T
)
(
m
/
T
)
\sum_{i=1}^n\sum_{j=1}^m(i,j)=\sum_{d=1}^nd\sum_{k=1}^{n/d}\mu(k)(n/kd)(m/kd)=\sum_{T=1}^n\phi(T)(n/T)(m/T)
∑i=1n∑j=1m(i,j)=∑d=1nd∑k=1n/dμ(k)(n/kd)(m/kd)=∑T=1nϕ(T)(n/T)(m/T)
3.
∑
i
[
(
n
,
i
)
=
1
]
i
=
(
ϕ
(
n
)
n
+
[
i
2
=
n
]
)
/
2
\sum_{i}[(n,i)=1]i=(\phi(n)n+[i^2=n])/2
∑i[(n,i)=1]i=(ϕ(n)n+[i2=n])/2
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 10000005
#define ll long long
#define mo 998244353
using namespace std;
int n,m,i,j,k,lim;
int tot,pri[maxn],bz[maxn],phi[maxn];
int f[maxn],g[maxn];
ll ans;
ll ksm(ll x,ll y){
ll s=1;
for(;y;y/=2,x=x*x%mo) if (y&1)
s=s*x%mo;
return s;
}
void getpri(){
phi[1]=1;
for(i=2;i<=lim;i++) {
if (!bz[i]) pri[++tot]=i,phi[i]=i-1;
for(j=1;j<=tot&&i*pri[j]<=lim;j++){
bz[i*pri[j]]=1;
if (i%pri[j]==0) {
phi[i*pri[j]]=phi[i]*pri[j];
break;
} else phi[i*pri[j]]=phi[i]*(pri[j]-1);
}
}
}
int main(){
freopen("ceshi.in","r",stdin);
// freopen("math.in","r",stdin);
// freopen("math.out","w",stdout);
scanf("%d%d",&n,&m),lim=max(n,m);
getpri();
for(i=1;i<=n;i++) f[i]=(ll)phi[i]*i%mo;
for(i=1;i<=m;i++) g[i]=(ll)phi[i]*i%mo;
for(i=1;i<=tot;i++){
int x=pri[i];
for(j=n/x*x;j;j-=x) (f[j/x]+=f[j])%=mo;
for(j=m/x*x;j;j-=x) (g[j/x]+=g[j])%=mo;
}
for(i=1;i<=lim;i++) f[i]=1ll*f[i]*g[i]%mo;
for(i=1;i<=tot;i++){
int x=pri[i];
for(j=x;j<=lim;j+=x) (f[j/x]-=f[j])%=mo;
}
// for(i=1;i<=lim;i++) f[i]=1ll*f[i]*ksm(phi[i],mo-2)%mo*ksm(i,n+1)%mo;
for(i=1;i<=tot;i++){
int p=pri[i];
ll mul=ksm(p,n+1)*ksm(p-1,mo-2)%mo;
ll inv=ksm(p,mo-2)*ksm(p,n+1)%mo;
for(j=p;j<=lim;j+=p){
int x=j/p; ll s=mul;
while (x%p==0) s=s*inv%mo,x/=p;
f[j]=(ll)f[j]*s%mo;
}
}
for(i=1;i<=lim;i++) ans+=f[i];
printf("%lld\n",(ans%mo+1+mo)*ksm(2,mo-2)%mo);
}


被折叠的 条评论
为什么被折叠?



