IV.Lcm
既然上一道题中的DZY都能自定义函数,那我们为什么不能呢?
定义\(f(x)\)为\(x\)中是否含有平方项。没有则为\(1\),有则为\(0\)。显然,它是积性函数。而我们要求的,就是
\(\sum_{i=1}^n\sum_{j=1}^m\dfrac{ij}{\gcd(i,j)}f(\gcd(i,j))\)
都是老一套了。做多了就发现都是这个德行。
\(\begin{aligned}&\sum_{i=1}^n\sum_{j=1}^m\dfrac{ij}{\gcd(i,j)}f(\gcd(i,j))\\=&\sum_{i=1}^n\sum_{j=1}^m\sum_{d=1}^{\min(n,m)}[\gcd(i,j)=d]\dfrac{ij}{d}f(d)\\=&\sum_{d=1}^{\min(n,m)}\sum_{i=1}^{n/d}\sum_{j=1}^{m/d}dij[\gcd(i,j)=1]f(d)\\=&\sum_{d=1}^{\min(n,m)}f(d)d\sum_{i=1}^{n/d}\sum_{j=1}^{m/d}ij[\gcd(i,j)=1]\\=&\sum_{d=1}^{\min(n,m)}f(d)d\sum_{i=1}^{n/d}\sum_{j=1}^{m/d}ij\sum_{x|i,x|j}\mu(x)\\=&\sum_{d=1}^{\min(n,m)}f(d)d\sum_{x=1}^{\min(n/d,m/d)}x^2\mu(x)\sum_{i=1}^{n/(dx)}\sum_{j=1}^{m/(dx)}ij\end{aligned}\)
我们设\(sum(x)=\dfrac{x(x+1)}{2}\)。
\(\begin{aligned}&\sum_{d=1}^{\min(n,m)}f(d)d\sum_{x=1}^{\min(n/d,m/d)}x^2\mu(x)\sum_{i=1}^{n/(dx)}\sum_{j=1}^{m/(dx)}ij\\=&\sum_{d=1}^{\min(n,m)}f(d)d\sum_{x=1}^{\min(n/d,m/d)}x^2\mu(x)sum(\dfrac{n}{dx})sum(\dfrac{m}{dx})\\=&\sum_{T=1}^{\min(n,m)}sum(\dfrac{n}{T})sum(\dfrac{m}{T})\sum_{d|T}f(d)d(\dfrac{T}{d})^2\mu(\dfrac{T}{d})\\=&\sum_{T=1}^{\min(n,m)}sum(\dfrac{n}{T})sum(\dfrac{m}{T})T\sum_{d|T}f(d)(\dfrac{T}{d})\mu(\dfrac{T}{d})\end{aligned}\)
我们设\(g(T)=T\sum_{d|T}f(d)(\dfrac{T}{d})\mu(\dfrac{T}{d})\)。因为\(f\)是积性函数,\(\mu(x)*id(x)\)(注意这里是数乘不是卷积)也是积性函数,因此\(g\)是积性函数。
我们考虑线性筛\(g\)。
设\(p\)为一质数,则\(g(p)=p*(f(1)*p*\mu(p)+f(p)*1*\mu(1))=p*(1-p)\)
考虑如何求出\(g(xp)\),其中\(p\)为一质数,\(x\)为任意数(保证大于\(p\))。
当\(\gcd(x,p)=1\),即\(x,p\)互质时,我们按照积性函数性质,有\(g(xp)=g(x)*g(p)\)。
否则,如果\(xp\)中含有三个及以上的因数\(p\),则\(f(xp)=0\),可以直接得出\(g(xp)=0\)。
否则,我们将\(xp\)分割成\(p^2\)和\(\dfrac{x}{p}\)两个必然互质的部分,运用积性函数性质,则有\(g(xp)=g(\dfrac{x}{p})*g(p^2)\)。
考虑如何求出\(g(p^2)\)。按照性质递推,会发现它等于\(-p^3\)。
当然咯,为了减少计算量,因为\(g(T)=T\sum_{d|T}f(d)(\dfrac{T}{d})\mu(\dfrac{T}{d})\),因此这个因子\(T\)我们统一留到最后加上。这时,有\(g(p)=(1-p),g(p^2)=-p\)(复辟)。
然后就直接整除分块即可。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=4e6;
int n,m,T,pri[N+5],g[N+5],res;
void init(){
g[1]=1;
for(int i=2;i<=N;i++){
if(!pri[i])pri[++pri[0]]=i,g[i]=1-i;
for(int j=1;j<=pri[0]&&i*pri[j]<=N;j++){
pri[i*pri[j]]=true;
if(!(i%pri[j])){
int r=i/pri[j];
if(r%pri[j])g[i*pri[j]]=-pri[j]*g[r];
break;
}
g[i*pri[j]]=g[i]*g[pri[j]];
}
}
for(int i=1;i<=N;i++)g[i]=g[i-1]+g[i]*i;
}
int main(){
scanf("%d",&T),init();
while(T--){
scanf("%d%d",&n,&m),res=0;
for(int l=1,r;l<=min(n,m);l=r+1)r=min(n/(n/l),m/(m/l)),res+=((1ll*(n/l)*(n/l+1)/2)*(1ll*(m/l)*(m/l+1)/2)*(g[r]-g[l-1]));
printf("%d\n",res&(~((1<<30)|(1<<31))));
}
return 0;
}