【题目地址】
题意简述
我们令 f ( n ) = ∑ d ∣ n μ ( d ) d f(n)=\sum_{d|n}\mu(d)d f(n)=∑d∣nμ(d)d,求下面式子在模 998244353 998244353 998244353后的值:
∑ i = 1 n ∑ j = 1 n f ( g c d ( i , j ) ) × f ( l c m ( i , j ) ) \sum_{i=1}^n\sum_{j=1}^nf(gcd(i,j))\times f(lcm(i,j)) i=1∑nj=1∑nf(gcd(i,j))×f(lcm(i,j))
其中 g c d gcd gcd为最大公约数, l c m lcm lcm为最小公倍数。
我们先来看一个例子:
求:
∑
i
=
1
n
∑
j
=
1
n
g
c
d
(
i
,
j
)
×
l
c
m
(
i
,
j
)
\sum_{i=1}^n\sum_{j=1}^ngcd(i,j)\times lcm(i,j)
i=1∑nj=1∑ngcd(i,j)×lcm(i,j)
很容易知道,这个可以这样变换:
∑ i = 1 n ∑ j = 1 n g c d ( i , j ) i j g c d ( i , j ) = ∑ i = 1 n ∑ j = 1 n i j = ( ∑ i = 1 n i ) ( ∑ j = 1 n j ) = ( ∑ i = 1 n i ) 2 \sum_{i=1}^n\sum_{j=1}^ngcd(i,j)\frac{ij}{gcd(i,j)} \\ =\sum_{i=1}^n\sum_{j=1}^nij \\ =\left(\sum_{i=1}^ni\right)\left(\sum_{j=1}^nj\right) \\\ \\ =\left(\sum_{i=1}^ni\right)^2 i=1∑nj=1∑ngcd(i,j)gcd(i,j)ij=i=1∑nj=1∑nij=(i=1∑ni)(j=1∑nj) =(i=1∑ni)2
所以我们看,原来的式子是否也能这样变换。
首先我们可以知道 f = ( μ ⋅ i d ) ∗ 1 f=(\mu\cdot id)*\mathbf 1 f=(μ⋅id)∗1(其中 ∗ * ∗为狄利克雷卷积)。
由于积性函数的乘积以及狄利克雷卷积仍旧为积性函数,所以 f f f也为积性函数。
那么我们考虑,对于一对 i , j i,j i,j,我们根据唯一分解定理,假设:
i = ∏ p x a x j = ∏ p y b y i=\prod p_x^{a_x} \\\ \\ j=\prod p_y^{b_y} i=∏pxax j=∏pyby
那么 f ( g c d ( i , j ) ) × f ( l c m ( i , j ) ) f(gcd(i,j))\times f(lcm(i,j)) f(gcd(i,j))×f(lcm(i,j))可以写成:
∏
f
(
p
w
m
i
n
(
a
w
,
b
w
)
)
∏
f
(
p
w
m
a
x
(
a
w
,
b
w
)
)
\prod f(p_w^{min(a_w,b_w)}) \prod f(p_w^{max(a_w,b_w)})
∏f(pwmin(aw,bw))∏f(pwmax(aw,bw))
(其中是因为积性函数
f
(
x
y
)
=
f
(
x
)
f
(
y
)
f(xy)=f(x)f(y)
f(xy)=f(x)f(y),在
x
⊥
y
x\perp y
x⊥y时(互质),所以将
i
,
j
i,j
i,j拆开)
那么我们将属于 i i i的放在一起,属于 j j j的放在一起,可以得到:
∏ f ( p x a x ) ∏ f ( p y a y ) = f ( i ) f ( j ) \prod f(p_x^{a_x})\prod f(p_y^{a_y}) \\ =f(i)f(j) ∏f(pxax)∏f(pyay)=f(i)f(j)
所以就可以按照前面的例子的做法,将其分开变换后可以得到,原式等于:
( ∑ i = 1 n f ( i ) ) 2 \left(\sum_{i=1}^n f(i)\right)^2 (i=1∑nf(i))2
那么现在我们考虑如何求 f f f的前缀和,由于 n ≤ 1 0 9 n\leq 10^9 n≤109,所以要用杜教筛。
我们看, f = ( μ ⋅ i d ) ∗ 1 f=(\mu\cdot id)*\mathbf 1 f=(μ⋅id)∗1,那么我们令 g = i d g=id g=id,则 f ∗ g f*g f∗g就等于:
f ∗ g = ( μ ⋅ i d ) ∗ 1 ∗ i d = ( μ ⋅ i d ) ∗ i d ∗ 1 = ( ∑ d ∣ n μ ( d ) d × n d ) ∗ 1 = ( n ∑ d ∣ n μ ( d ) ) ∗ 1 = ( i d ⋅ ϵ ) ∗ 1 = ϵ ∗ 1 = 1 \begin{aligned} f*g=&(\mu\cdot id)*\mathbf 1 * id \\ =&(\mu\cdot id)*id*\mathbf 1 \\ =&\left(\sum_{d|n}\mu(d)d\times \frac{n}{d}\right)*\mathbf 1 \\ =& \left(n\sum_{d|n}\mu(d)\right)*\mathbf 1 \\ =&(id\cdot \epsilon )*\mathbf 1 \\ =&\epsilon * \mathbf 1 \\ =& \mathbf 1 \end{aligned} f∗g=======(μ⋅id)∗1∗id(μ⋅id)∗id∗1⎝⎛d∣n∑μ(d)d×dn⎠⎞∗1⎝⎛nd∣n∑μ(d)⎠⎞∗1(id⋅ϵ)∗1ϵ∗11
那么我们将其带入杜教筛的公式,可以得到前缀和等于:
S ( n ) = ∑ i = 1 n 1 − ∑ i = 2 n i S ( ⌊ n i ⌋ ) S(n)=\sum_{i=1}^n 1-\sum_{i=2}^ni S(\lfloor\frac{n}{i}\rfloor) S(n)=i=1∑n1−i=2∑niS(⌊in⌋)
我们预处理 n 2 3 n^{\frac{2}{3}} n32的前缀和,然后杜教筛就好啦。
关于 f f f的线性筛,方法如下:
因为当 μ ( p c ) \mu(p^c) μ(pc)中 c > 1 c>1 c>1时 μ ( p c ) = 0 \mu(p^c)=0 μ(pc)=0,所以原式为:
f
(
p
c
)
=
∑
i
=
0
c
μ
(
p
i
)
p
i
=
1
−
p
f(p^c)=\sum_{i=0}^c\mu(p^i)p^i=1-p
f(pc)=i=0∑cμ(pi)pi=1−p
根据积性函数定义:
f
(
p
c
)
=
1
−
p
f
(
x
×
p
c
)
=
f
(
p
c
)
f
(
x
)
[
x
⊥
p
c
]
f(p^c)=1-p \\ f(x\times p^c)=f(p^c)f(x)[x\perp p^c]
f(pc)=1−pf(x×pc)=f(pc)f(x)[x⊥pc]
所以这个题就可以在 O ( n 2 3 ) O(n^{\frac{2}{3}}) O(n32)时间内解决了。
#include<map>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int M=1e6+10;
const ll Mod=1e9+7;
ll prime[M],mu[M],cnt;
bool vis[M];
ll F[M],c[M],f[M],inv_2;
ll fpow(ll a,ll b){
ll res=1;
for(;b;b>>=1,a=(a*a)%Mod){
if(b&1)res=(res*a)%Mod;
}
return res;
}
void init(){
inv_2=fpow(2,Mod-2);
F[1]=1;
for(ll i=2;i<M;i++){
if(!vis[i]){
prime[++cnt]=i;
F[i]=((1-i)%Mod+Mod)%Mod;
c[i]=i;f[i]=i;
}
for(ll j=1,v;j<=cnt&&i*prime[j]<M;j++){
v=i*prime[j];
vis[v]=1;
if(!(i%prime[j])){
c[v]=c[i]*f[i];f[v]=f[i];
F[v]=F[v/c[v]]*F[prime[j]]%Mod;
break;
}
F[v]=F[i]*F[prime[j]]%Mod;
c[v]=prime[j];f[v]=prime[j];
}
}
for(ll i=2;i<M;i++){
F[i]=(F[i-1]+F[i])%Mod;
}
}
ll S(ll x){return ((x*(x+1))%Mod)*inv_2%Mod;}
ll Sarea(ll L,ll R){return ((S(R)-S(L-1))%Mod+Mod)%Mod;}
map <ll,ll> mp;
ll calc(ll x){
if(x<M) return F[x];
if(mp.count(x)) return mp[x];
ll ans=x;
for(ll i=2,j;i<=x;i=j+1){
j=(x/(x/i));
ans=(ans-(Sarea(i,j)*calc(x/i))%Mod)%Mod;
}
if(ans<0)ans+=Mod;
return mp[x]=ans;
}
ll n;
ll Sqr(ll a){return a*a%Mod;}
int main(){
scanf("%lld",&n);
init();
printf("%lld\n",Sqr(calc(n)));
return 0;
}