链接
思路
上次做这题的时候用了一些玄学水过去了,这次我写了个有理有据的
O(n+TN−−√)
O
(
n
+
T
N
)
算法,
假设n < m,根据题意写出
ans=∑i=1n∑j=1mij(i,j)μ2((i,j))
a
n
s
=
∑
i
=
1
n
∑
j
=
1
m
i
j
(
i
,
j
)
μ
2
(
(
i
,
j
)
)
=∑d=1ndμ2(d)∑i=1⌊nd⌋∑j=1⌊md⌋ij[(i,j)=1]
=
∑
d
=
1
n
d
μ
2
(
d
)
∑
i
=
1
⌊
n
d
⌋
∑
j
=
1
⌊
m
d
⌋
i
j
[
(
i
,
j
)
=
1
]
=∑d=1ndμ2(d)∑i=1⌊nd⌋∑j=1⌊md⌋ij∑x|(i,j)μ(x)
=
∑
d
=
1
n
d
μ
2
(
d
)
∑
i
=
1
⌊
n
d
⌋
∑
j
=
1
⌊
m
d
⌋
i
j
∑
x
|
(
i
,
j
)
μ
(
x
)
=∑d=1ndμ2(d)∑x=1⌊nd⌋μ(x)∑x|i⌊nd⌋∑x|j⌊md⌋ij
=
∑
d
=
1
n
d
μ
2
(
d
)
∑
x
=
1
⌊
n
d
⌋
μ
(
x
)
∑
x
|
i
⌊
n
d
⌋
∑
x
|
j
⌊
m
d
⌋
i
j
令 g(x)=∑xi=1i=x(x+1)2 g ( x ) = ∑ i = 1 x i = x ( x + 1 ) 2
ans=∑d=1ndμ2(d)∑x=1⌊nd⌋x2μ(x)g(⌊ndx⌋)g(⌊mdx⌋)
a
n
s
=
∑
d
=
1
n
d
μ
2
(
d
)
∑
x
=
1
⌊
n
d
⌋
x
2
μ
(
x
)
g
(
⌊
n
d
x
⌋
)
g
(
⌊
m
d
x
⌋
)
这种情况下直接做是 O(TN) O ( T N ) 的
因为每次查询 n n 和都在变,因此无法预处理式子后面的那一段,考虑如何把 n n 和从后面拿出来,然后再通过预处理一些和 n n ,无关的部分来降低每次询问的计算次数
令 t=dx t = d x
ans=∑d=1nμ2(d)∑d|tnt2dμ(td)g(⌊nt⌋)g(⌊mt⌋)
a
n
s
=
∑
d
=
1
n
μ
2
(
d
)
∑
d
|
t
n
t
2
d
μ
(
t
d
)
g
(
⌊
n
t
⌋
)
g
(
⌊
m
t
⌋
)
=∑t=1ng(⌊nt⌋)g(⌊mt⌋)t∑d|ttdμ(td)μ2(d)
=
∑
t
=
1
n
g
(
⌊
n
t
⌋
)
g
(
⌊
m
t
⌋
)
t
∑
d
|
t
t
d
μ
(
t
d
)
μ
2
(
d
)
这里就看出来了,只要预处理后面那一坨 t∑d|ttdμ(td)μ2(d) t ∑ d | t t d μ ( t d ) μ 2 ( d ) ,每次就可以 O(N−−√) O ( N ) 了
这题最麻烦的就在这里,这个东西要分好几层来看,首先令 f(x)=xμ(x) f ( x ) = x μ ( x ) ,那么上面那一坨就等于 t(f∗μ2)(t) t ( f ∗ μ 2 ) ( t ) ,其中 ∗ ∗ 是狄利克雷卷积符号。
肯定是积性函数, μ2(x) μ 2 ( x ) 也是积性函数,因此 (f∗μ2)(x) ( f ∗ μ 2 ) ( x ) 也是积性函数,外面那个 x x 最后再乘就行。
令
现在有两种线性筛来求出 u(x) u ( x ) :
一种是只记录 h(x) h ( x ) ,试图用 h(x) h ( x ) 的值来推导出 h(x⋅pr(x)) h ( x ⋅ p r ( x ) ) ,其中 pr(x) p r ( x ) 是指 x x 的最小质因子,这种只适合于求非完全积性函数和完全积性函数的狄利克雷卷积,这里两个函数都是非完全积性函数的,因此用另一种方法
第二种方法记录每个数的最小质因子和最小质因子的幂 p(x) p ( x ) , p(x) p ( x ) 的意义是对 x x 不断地除以,直到无法整除,假设做除法的次数是 q q 那么。这样可以把一个数分成互质的两部分 xp(x) x p ( x ) 和 p(x) p ( x ) ,则 h(x)=h(xp(x))h(p(x)) h ( x ) = h ( x p ( x ) ) h ( p ( x ) ) ,但是这种方法的缺点是当 p(x)=x p ( x ) = x 时,无法直接求出 h(x) h ( x ) ,必须要根据不同函数的特殊性来推导 h(x) h ( x ) 的值。
设 p(x)=prq(x) p ( x ) = p r q ( x ) ,
当 q=2 q = 2 时, h(x)=f(1)μ2(pr2(x))+f(pr(x))μ2(pr(x))+f(pr2(x))μ(1)=−pr(x) h ( x ) = f ( 1 ) μ 2 ( p r 2 ( x ) ) + f ( p r ( x ) ) μ 2 ( p r ( x ) ) + f ( p r 2 ( x ) ) μ ( 1 ) = − p r ( x )
当 q=3 q = 3 时, h(x)=f(1)μ2(pr3(x))+⋅⋅⋅+f(pr3(x))μ2(1)=0 h ( x ) = f ( 1 ) μ 2 ( p r 3 ( x ) ) + ⋅ ⋅ ⋅ + f ( p r 3 ( x ) ) μ 2 ( 1 ) = 0
当 q>3 q > 3 时,同理 h(x)=0 h ( x ) = 0
这样就知道了,当 x=pr2(x) x = p r 2 ( x ) 时, h(x)=−pr(x) h ( x ) = − p r ( x ) 而当 x=p(x)>pr2(x) x = p ( x ) > p r 2 ( x ) 时 h(x)=0 h ( x ) = 0
然后就可以线性筛了,总的时间复杂度是 O(N+TN−−√) O ( N + T N )
代码
//线性筛、莫比乌斯反演
#include <cstdio>
#include <algorithm>
#define maxn 4000010
#define mod 1073741824ll
#define ll long long
using namespace std;
ll prime[maxn], g[maxn], u[maxn], pr[maxn], p[maxn];
bool mark[maxn];
void init()
{
ll i, j, t;
u[1]=1;
for(i=2;i<maxn;i++)
{
if(!mark[i])
{
prime[++*prime]=i;
pr[i]=p[i]=i;
u[i]=(-i+1+mod)%mod;
}
else
{
u[i]=u[i/p[i]]*u[p[i]]%mod;
if(i==pr[i]*pr[i])u[i]=(-pr[i]+mod)%mod;
}
for(j=1;j<=*prime and i*prime[j]<maxn;j++)
{
t=i*prime[j];
mark[t]=1;
pr[t]=prime[j];
if(i%prime[j]==0)p[t]=p[i]*prime[j];
else p[t]=prime[j];
if(i%prime[j]==0)break;
}
}
for(i=1;i<maxn;i++)g[i]=i*(i+1)/2%mod;
for(i=1;i<maxn;i++)u[i]=u[i]*i%mod;
for(i=1;i<maxn;i++)u[i]=(u[i]+u[i-1])%mod;
}
void calc(ll n, ll m)
{
ll t, last;
ll ans=0;
if(n<m)swap(n,m);
for(t=1;t<=m;t=last+1)
{
last=min(n/(n/t),m/(m/t));
ans=(ans+(g[n/t]*g[m/t])%mod*(u[last]-u[t-1]+mod)%mod)%mod;
}
printf("%lld\n",ans);
}
int main()
{
ll T, n, m;
init();
scanf("%lld",&T);
while(T--){scanf("%lld%lld",&n,&m);calc(n,m);}
return 0;
}