题目大意
共有 T T T 组数据,给定 n , m n,m n,m,设 d ( x ) = ∑ i ∣ x 1 d(x)=\sum_{i|x}1 d(x)=∑i∣x1,求 ∑ i = 1 n ∑ j = 1 m d ( i j ) \sum_{i=1}^n\sum_{j=1}^md(ij) i=1∑nj=1∑md(ij)
数据范围 T = 1 ( 不输入 ) , 1 ⩽ n = m ( 不输入 ) ⩽ 1 0 9 T=1(不输入),1\leqslant n=m(不输入)\leqslant 10^9 T=1(不输入),1⩽n=m(不输入)⩽109 或 1 ⩽ n , m , T ⩽ 50000 1\leqslant n,m,T\leqslant 50000 1⩽n,m,T⩽50000
题解
由于两道题目有一定不同,这里考虑最大范围,但不管如何,先来证证证……
结论 d ( i j ) = ∑ x ∣ i ∑ y ∣ j [ ( x , y ) = 1 ] \begin{aligned}d(ij)=\sum_{x|i}^{^{^{^{^{}}}}}\sum_{y|j}[(x,y)=1]\end{aligned} d(ij)=x∣i∑y∣j∑[(x,y)=1]
证明 对于
i
j
ij
ij,其唯一分解为
i
j
=
∏
d
=
1
n
p
d
k
d
\begin{aligned}ij=\prod\limits_{d=1}^{\ n^{^{^{^{}}}}}p_d^{k_d}\end{aligned}
ij=d=1∏ npdkd,则
d
(
i
j
)
=
∏
d
=
1
n
(
k
d
+
1
)
\begin{aligned}d(ij)=\prod\limits_{d=1}^{\ n^{^{^{^{}}}}}(k_d+1)\end{aligned}
d(ij)=d=1∏ n(kd+1)。
考虑一个质数
p
p
p 对
d
(
i
j
)
d(ij)
d(ij) 的贡献,设
i
=
p
k
∗
t
1
,
j
=
p
q
∗
t
2
i=p^k*t_1,j=p^q*t_2
i=pk∗t1,j=pq∗t2,则对
d
(
i
j
)
d(ij)
d(ij) 的贡献为
k
+
q
+
1
k+q+1
k+q+1。
再来看一个引理。
引理 设
i
=
p
k
∗
t
1
,
j
=
p
q
∗
t
2
i=p^k*t_1,j=p^q*t_2
i=pk∗t1,j=pq∗t2,则有:
∑
x
=
0
k
∑
y
=
0
q
[
(
p
x
,
p
y
)
=
1
]
=
q
+
k
+
1
\begin{aligned}\sum\limits_{x=0}^k\sum\limits_{y=0}^q[(p^x,p^y)=1]=q+k+1\end{aligned}
x=0∑ky=0∑q[(px,py)=1]=q+k+1
证明 可以发现,当且仅当
x
y
=
0
xy=0
xy=0 时,
(
p
x
,
p
y
)
=
1
(p^x,p^y)=1
(px,py)=1,故成立。
因此对质数
p
p
p 对
d
(
i
,
j
)
d(i,j)
d(i,j) 的贡献的贡献为
∑
x
=
0
k
∑
y
=
0
q
[
(
p
x
,
p
y
)
=
1
]
\begin{aligned}\sum\limits_{x=0}^k\sum\limits_{y=0}^q[(p^x,p^y)=1]\end{aligned}
x=0∑ky=0∑q[(px,py)=1] 。
接下来设
i
=
∏
i
=
1
n
p
i
k
i
,
j
=
∏
i
=
1
n
p
i
q
i
\begin{aligned}i=\prod_{i=1}^n\limits p_i^{k_i},j=\prod_{i=1}^{n^{^{^{^{}}}}}\limits p_i^{q_i}\end{aligned}
i=i=1∏npiki,j=i=1∏npiqi,考虑下面逐一每一个质数
p
i
p_i
pi,根据乘法原理得:
d
(
i
j
)
=
∑
x
1
=
0
k
1
∑
y
1
=
0
q
1
[
(
p
1
x
1
,
p
1
y
1
)
=
1
]
∑
x
2
=
0
k
2
∑
y
2
=
0
q
2
[
(
p
2
x
2
,
p
2
y
2
)
=
1
]
.
.
.
∑
x
n
=
0
k
n
∑
y
n
=
0
q
n
[
(
p
n
x
n
,
p
n
y
n
)
=
1
]
d(ij)=\sum_{x_1=0}^{k_1}\sum_{y_1=0}^{q_1}[(p_1^{x_1},p_1^{y_1})=1]\sum_{x_2=0}^{k_2}\sum_{y_2=0}^{q_2}[(p_2^{x_2},p_2^{y_2})=1]...\sum_{x_n=0}^{k_n}\sum_{y_n=0}^{q_n}[(p_n^{x_n},p_n^{y_n})=1]
d(ij)=x1=0∑k1y1=0∑q1[(p1x1,p1y1)=1]x2=0∑k2y2=0∑q2[(p2x2,p2y2)=1]...xn=0∑knyn=0∑qn[(pnxn,pnyn)=1]
即 d ( i j ) = ∑ d = 1 n ∑ x d = 0 k d ∑ y d = 0 q d [ ( p d x d , p d y d ) = 1 ] d(ij)=\sum_{d=1}^n\sum_{x_d=0}^{k_d}\sum_{y_d=0}^{q_d}[(p_d^{x_d},p_d^{y_d})=1] d(ij)=d=1∑nxd=0∑kdyd=0∑qd[(pdxd,pdyd)=1]
可以发现,对于下面这个式子
∑
x
∣
i
∑
y
∣
j
[
(
x
,
y
)
=
1
]
\sum_{x|i}\sum_{y|j}[(x,y)=1]
x∣i∑y∣j∑[(x,y)=1]
如果
x
x
x 和
y
y
y 含有的不相同的质因子,它们不会对答案造成任何影响,因而相当于仅仅枚举了两者相同的质因子的个数,因此,我们有
∑
x
∣
i
∑
y
∣
j
[
(
x
,
y
)
=
1
]
=
∑
d
=
1
n
∑
x
d
=
0
k
d
∑
y
d
=
0
q
d
[
(
p
d
x
d
,
p
d
y
d
)
=
1
]
\sum_{x|i}\sum_{y|j}[(x,y)=1]=\sum_{d=1}^n\sum_{x_d=0}^{k_d}\sum_{y_d=0}^{q_d}[(p_d^{x_d},p_d^{y_d})=1]
x∣i∑y∣j∑[(x,y)=1]=d=1∑nxd=0∑kdyd=0∑qd[(pdxd,pdyd)=1]
因而 d ( i j ) = ∑ x ∣ i ∑ y ∣ j [ ( x , y ) = 1 ] d(ij)=\sum_{x|i}\sum_{y|j}[(x,y)=1] d(ij)=x∣i∑y∣j∑[(x,y)=1]得证。
代入题目,得:
∑
i
=
1
n
∑
j
=
1
m
d
(
i
j
)
=
∑
i
=
1
n
∑
j
=
1
m
∑
x
∣
i
∑
y
∣
j
[
(
x
,
y
)
=
1
]
=
∑
i
=
1
n
∑
j
=
1
m
∑
x
∣
i
∑
y
∣
j
∑
d
∣
(
x
,
y
)
μ
(
d
)
\begin{aligned} \sum_{i=1}^n\sum_{j=1}^md(ij)&=\sum_{i=1}^n\sum_{j=1}^m\sum_{x|i}\sum_{y|j}[(x,y)=1]\\ &=\sum_{i=1}^n\sum_{j=1}^m\sum_{x|i}\sum_{y|j}\sum_{d|(x,y)}\mu(d)\\ \end{aligned}
i=1∑nj=1∑md(ij)=i=1∑nj=1∑mx∣i∑y∣j∑[(x,y)=1]=i=1∑nj=1∑mx∣i∑y∣j∑d∣(x,y)∑μ(d)
各回各家,各找各妈,好好理解,实在不行用C++证明法。
原式
=
∑
d
=
1
min
(
n
,
m
)
μ
(
d
)
(
∑
d
∣
x
x
⩽
n
∑
x
∣
i
i
⩽
n
1
)
(
∑
d
∣
y
y
⩽
m
∑
y
∣
j
i
⩽
m
1
)
=
∑
d
=
1
min
(
n
,
m
)
μ
(
d
)
(
∑
d
∣
x
x
⩽
n
⌊
n
x
⌋
)
(
∑
d
∣
y
y
⩽
m
⌊
m
y
⌋
)
=
∑
d
=
1
min
(
n
,
m
)
μ
(
d
)
(
∑
x
=
1
⌊
n
d
⌋
⌊
n
d
x
⌋
)
(
∑
y
=
1
⌊
m
d
⌋
⌊
m
d
y
⌋
)
=
∑
d
=
1
min
(
n
,
m
)
μ
(
d
)
(
∑
x
=
1
⌊
n
d
⌋
⌊
⌊
n
d
⌋
x
⌋
)
(
∑
y
=
1
⌊
m
d
⌋
⌊
⌊
m
d
⌋
y
⌋
)
\begin{aligned} 原式&=\sum_{d=1}^{\min(n,m)}\mu(d)\left(\sum_{d|x}^{x\leqslant n}\sum_{x|i}^{i\leqslant n}1\right)\left(\sum_{d|y}^{y\leqslant m}\sum_{y|j}^{i\leqslant m}1\right)\\ &=\sum_{d=1}^{\min(n,m)}\mu(d)\left(\sum_{d|x}^{x\leqslant n}\left\lfloor\frac nx\right\rfloor\right)\left(\sum_{d|y}^{y\leqslant m}\left\lfloor\frac my\right\rfloor\right)\\ &=\sum_{d=1}^{\min(n,m)}\mu(d)\left(\sum_{x=1}^{\large\lfloor\frac nd\rfloor}\left\lfloor\frac n{dx}\right\rfloor\right)\left(\sum_{y=1}^{\left\lfloor\frac md\right\rfloor}\left\lfloor\frac m{dy}\right\rfloor\right)\\ &=\sum_{d=1}^{\min(n,m)}\mu(d)\left(\sum_{x=1}^{\left\lfloor\frac nd\right\rfloor}\left\lfloor\frac {\left\lfloor\frac nd\right\rfloor}{x}\right\rfloor\right)\left(\sum_{y=1}^{\left\lfloor\frac md\right\rfloor}\left\lfloor\frac {\left\lfloor\frac md\right\rfloor}{y}\right\rfloor\right) \end{aligned}
原式=d=1∑min(n,m)μ(d)⎝
⎛d∣x∑x⩽nx∣i∑i⩽n1⎠
⎞⎝
⎛d∣y∑y⩽my∣j∑i⩽m1⎠
⎞=d=1∑min(n,m)μ(d)⎝
⎛d∣x∑x⩽n⌊xn⌋⎠
⎞⎝
⎛d∣y∑y⩽m⌊ym⌋⎠
⎞=d=1∑min(n,m)μ(d)⎝
⎛x=1∑⌊dn⌋⌊dxn⌋⎠
⎞⎝
⎛y=1∑⌊dm⌋⌊dym⌋⎠
⎞=d=1∑min(n,m)μ(d)⎝
⎛x=1∑⌊dn⌋⌊x⌊dn⌋⌋⎠
⎞⎝
⎛y=1∑⌊dm⌋⌊y⌊dm⌋⌋⎠
⎞
Luogu
Θ ( n n ) \Theta(n\sqrt n) Θ(nn)预处理出 f ( x ) = ∑ i = 1 n ⌊ n i ⌋ f(x)=\sum_{i=1}^n\lfloor\frac ni\rfloor f(x)=∑i=1n⌊in⌋,线筛出 μ \mu μ 即可,胜在代码短。
#include<bits/stdc++.h>
using namespace std;
#define maxn 50010
long long Sqrt[maxn];
long long s_sqrt(long long n){
long long ans=0;
for(long long l=1,r;l<=n;l=r+1){
r=min(n/(n/l),n);
ans+=(r-l+1)*(n/l);
} return ans;
}
long long p[maxn],vis[maxn],mu[maxn],smu[maxn],calced=-1;
void euler(long long n=maxn-10){
calced=n;
long long tot=0;
memset(vis,0,sizeof vis);
mu[1]=1;
for(long long i=2;i<=n;i++){
if(vis[i]==0) p[++tot]=i,mu[i]=-1;
for(long long j=1;j<=tot&&i*p[j]<=n;j++){
vis[i*p[j]]=1;
if(i%p[j]==0){
mu[p[j]*i]=0;
break;
} else mu[p[j]*i]=-mu[i];
}
} smu[0]=0;
for(long long i=1;i<=n;i++)
smu[i]=smu[i-1]+mu[i];
}
long long T,n,m;
signed main(void){
euler(50000);
for(int i=1;i<=maxn;i++)
Sqrt[i]=s_sqrt(i);
scanf("%lld",&T);
while(T--){
scanf("%lld%lld",&n,&m);
long long ans=0;
for(long long l=1,r;l<=min(n,m);l=r+1){
r=min(min(n/(n/l),m/(m/l)),min(n,m));
ans+=(smu[r]-smu[l-1])*Sqrt[n/l]*Sqrt[m/l];
} printf("%lld\n",ans);
}
return 0;
}
还能更好吗?这个时间几乎时卡着过去的。当然可以。有
∑
i
=
1
n
⌊
n
i
⌋
=
∑
i
=
1
n
∑
i
∣
k
k
⩽
n
1
=
∑
k
=
1
n
∑
i
∣
k
1
=
∑
k
=
1
n
d
(
k
)
\begin{aligned}\sum_{i=1}^n\left\lfloor\frac ni\right\rfloor &=\sum_{i=1}^n\sum_{i|k}^{k\leqslant n}1\\ &=\sum_{k=1}^n\sum_{i|k}1\\ &=\sum_{k=1}^nd(k)\\ \end{aligned}
i=1∑n⌊in⌋=i=1∑ni∣k∑k⩽n1=k=1∑ni∣k∑1=k=1∑nd(k)
其中 d d d 是约数和函数。 d d d 可以在 Θ ( n ) \Theta(n) Θ(n) 的时间内筛出来,时间复杂度为 Θ ( n + T n ) \Theta(n+T\sqrt n) Θ(n+Tn)。
#include<bits/stdc++.h>
using namespace std;
#define maxn 50010
long long low[maxn],d[maxn],sd[maxn];
long long p[maxn],vis[maxn],mu[maxn],smu[maxn],calced=-1;
void euler(long long n=maxn-10){
calced=n;
long long tot=0;
memset(vis,0,sizeof vis);
mu[1]=1;smu[1]=1;d[1]=1;low[1]=1;sd[1]=1;
for(long long i=2;i<=n;i++){
if(vis[i]==0) low[i]=p[++tot]=i,mu[i]=-1,d[i]=2;
for(long long j=1;j<=tot&&i*p[j]<=n;j++){
vis[i*p[j]]=1;
if(i%p[j]==0){
low[i*p[j]]=low[i]*p[j];
if(low[i]==i) d[i*p[j]]=d[i]+1;
else d[i*p[j]]=d[i/low[i]]*d[low[i]*p[j]];
mu[p[j]*i]=0;
break;
} mu[p[j]*i]=-mu[i];
low[i*p[j]]=p[j];
d[i*p[j]]=d[i]*d[p[j]];
} smu[i]=smu[i-1]+mu[i];
sd[i]=sd[i-1]+d[i];
}
}
long long T,n,m;
signed main(void){
euler();
scanf("%lld",&T);
while(T--){
scanf("%lld%lld",&n,&m);
long long ans=0;
for(long long l=1,r;l<=min(n,m);l=r+1){
r=min(min(n/(n/l),m/(m/l)),min(n,m));
ans+=(smu[r]-smu[l-1])*sd[n/l]*sd[m/l];
} printf("%lld\n",ans);
}
return 0;
}
BZOJ
%
BZOJ 要求设计非线性算法,因而
μ
\mu
μ 的前缀和需要用杜教筛求出,由于
n
=
m
n=m
n=m,有:
∑
d
=
1
min
(
n
,
m
)
μ
(
d
)
(
∑
x
=
1
⌊
n
d
⌋
⌊
⌊
n
d
⌋
x
⌋
)
(
∑
y
=
1
⌊
m
d
⌋
⌊
⌊
m
d
⌋
y
⌋
)
=
∑
d
=
1
min
(
n
,
m
)
μ
(
d
)
(
∑
x
=
1
⌊
n
d
⌋
⌊
⌊
n
d
⌋
x
⌋
)
2
\sum_{d=1}^{\min(n,m)}\mu(d)\Bigg(\sum_{x=1}^{\large\lfloor\frac nd\rfloor}\Big\lfloor\frac {\large\lfloor\frac nd\rfloor}{x}\Big\rfloor\Bigg)\Bigg(\sum_{y=1}^{\large\lfloor\frac md\rfloor}\Big\lfloor\frac {\large\lfloor\frac md\rfloor}{y}\Big\rfloor\Bigg)=\sum_{d=1}^{\min(n,m)}\mu(d)\Bigg(\sum_{x=1}^{\large\lfloor\frac nd\rfloor}\Big\lfloor\frac {\large\lfloor\frac nd\rfloor}{x}\Big\rfloor\Bigg)^2
d=1∑min(n,m)μ(d)(x=1∑⌊dn⌋⌊x⌊dn⌋⌋)(y=1∑⌊dm⌋⌊y⌊dm⌋⌋)=d=1∑min(n,m)μ(d)(x=1∑⌊dn⌋⌊x⌊dn⌋⌋)2 这样求第二个sigma的时间复杂度为:
T
(
n
)
=
Θ
(
⌊
n
d
⌋
)
T(n)=\Theta\left(\sqrt{\left\lfloor\frac{n}{d}\right\rfloor}\right)
T(n)=Θ(⌊dn⌋) 因而计算这个sigma的总时间复杂度为
T
(
n
)
=
Θ
(
n
1
)
+
Θ
(
n
2
)
+
.
.
.
+
Θ
(
n
n
)
=
Θ
(
n
3
4
)
T(n)=\Theta\left(\sqrt\frac n1\right)+\Theta\left(\sqrt\frac n2\right)+...+\Theta\left(\sqrt\frac n{\sqrt n}\right)=\Theta\left(n^{\normalsize\frac34}\right)
T(n)=Θ(1n)+Θ(2n)+...+Θ(nn)=Θ(n43) 因而总时间复杂度为
T
(
n
)
=
Θ
(
n
2
3
+
n
3
4
)
T(n)=\Theta\left(n^{\normalsize\frac 23}+n^{\normalsize \frac 34}\right)
T(n)=Θ(n32+n43)
#include<bits/stdc++.h>
using namespace std;
#define maxn 2000000
#define mod 1000000007
long long s_sqrt(long long n){
long long ans=0;
for(long long l=1,r;l<=n;l=r+1){
r=n/(n/l);
ans=(ans+(r-l+1)*(n/l))%mod;
} return ans*ans%mod;
}
long long p[maxn],vis[maxn],mu[maxn],smu[maxn],calced=-1;
void euler(long long n=maxn-10){
calced=n;
long long tot=0;
memset(vis,0,sizeof vis);
mu[1]=1;smu[1]=1;
for(long long i=2;i<=n;i++){
if(vis[i]==0) p[++tot]=i,mu[i]=-1;
for(long long j=1;j<=tot&&i*p[j]<=n;j++){
vis[i*p[j]]=1;
if(i%p[j]==0){
mu[p[j]*i]=0;
break;
} else mu[p[j]*i]=mod-mu[i];
} smu[i]=(smu[i-1]+mu[i]+mod)%mod;
}
}
map<long long,long long> Smu;
long long Sum_mu(long long n){
if(n<=calced) return smu[n];
map<long long,long long>::iterator it=Smu.find(n);
if(it!=Smu.end()) return it->second;
long long ans=1;
for(long long l=2,r;l<=n;l=r+1){
r=n/(n/l);
ans=(ans-Sum_mu(n/l)*(r-l+1)%mod+mod)%mod;
} return Smu[n]=ans%mod;
}
long long n;
signed main(void){
euler();
scanf("%lld",&n);
long long ans=0;
for(long long l=1,r;l<=n;l=r+1){
r=n/(n/l);
ans=(ans+(Sum_mu(r)-Sum_mu(l-1)+mod)%mod*s_sqrt(n/l)%mod)%mod;
} printf("%lld\n",ans%mod);
return 0;
}