题目描述
题解
是时候又写一大坨推导公式了。
首先设
s(x,y)=∑i=1x∑j=1yij[gcd(i,j)=1]
并且 x<y
利用莫比乌斯反演变形
s(x,y)=∑i=1x∑j=1yij∑d=1x[d|i][d|j]μ(d)
令i=id j=jd
s(x,y)=∑d=1xμ(d)d2∑i=1xd∑j=1ydij
再设
sum(x,y)=∑i=1x∑j=1yij
利用等差数列求和公式
sum(x,y)=x(x+1)2∗y(y+1)2
将sum函数代入s函数得
s(x,y)=∑d=1xμ(d)d2sum(⌊xd⌋,⌊yd⌋)
好我们现在回到题目
∑i=1n∑j=1mlcm[i,j]
设 n<m
那么
∑i=1n∑j=1mijgcd(i,j)
∑i=1n∑j=1mij∑d=1n[d|i][d|j][gcd(i,j)=d]1d
令i=id j=jd
∑d=1n∑i=1ndid∑j=1mdjd[gcd(i,j)=1]1d
∑d=1nd∑i=1nd∑j=1mdij[gcd(i,j)=1]
将s函数代入这个式子得到
∑d=1nds(⌊nd⌋,⌊md⌋)
sum函数可以在
O(1)
的时间得到
s函数最多有
n−−√+m−−√
种取值,可以在
O(n−−√+m−−√)
的时间得到
那么答案也只有
n−−√+m−−√
种取值,同样可以在
O(n−−√+m−−√)
的时间得到,所以时间复杂度是接近
O(n)
的
代码
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define LL long long
const int max_n=1e7+5;
const LL Mod=20101009;
LL n,m,x,y,xx,yy,k,jj,sum,ans,s[max_n];
int mu[max_n],prime[max_n],p[max_n];
inline void get_mu(){
mu[1]=1;
for (int i=2;i<=n;++i){
if (!p[i]){
prime[++prime[0]]=i;
mu[i]=-1;
}
for (int j=1;j<=prime[0]&&i*prime[j]<=n;++j){
p[i*prime[j]]=1;
if (i%prime[j]==0){
mu[i*prime[j]]=0;
break;
}
else mu[i*prime[j]]=-mu[i];
}
}
for (LL i=1;i<=n;i++) s[i]=(LL)(s[i-1]+(LL)(i*i*mu[i])%Mod)%Mod;
}
inline LL Sum(LL x,LL y){
LL w1=((x+1)*x/2)%Mod;
LL w2=((y+1)*y/2)%Mod;
return w1*w2%Mod;
}
int main(){
scanf("%lld%lld",&n,&m); if (n>m) swap(n,m);
get_mu(); jj=0;
for (LL i=1;i<=n;i=jj+1){
jj=min(n/(n/i),m/(m/i));
x=n/i,y=m/i; if (x>y) swap(x,y);
k=0; sum=0;
for (LL j=1;j<=x;j=k+1){
k=min(x/(x/j),y/(y/j));
xx=x/j; yy=y/j;
sum=(sum+((s[k]-s[j-1])%Mod*Sum(xx,yy)%Mod)%Mod)%Mod;
}
ans=(ans+(((i+jj)*(jj-i+1)/2)%Mod*sum%Mod)%Mod)%Mod;
}
printf("%lld\n",(ans+Mod)%Mod);
}