依题意: d=gcd(i,j)
Ans=∑ni=1∑mj=1Lcm(i,j)=∑ni=1∑mj=1id∗jd∗d
⇒Ans=∑min(n,m)d=1d∗∑⌊nd⌋i=1∑⌊md⌋j=1i∗j|gcd(i,j)=1
⇒Ans=∑min(n,m)d=1d∗∑⌊nd⌋i=1∑⌊md⌋j=1i∗j∗∑p|i,p|jμ(p)
⇒Ans=∑min(n,m)d=1d∗∑⌊min(nd,md)⌋p=1μ(p)∗p2∗∑⌊ndp⌋i=1∑⌊mdp⌋j=1i∗j
枚举d,对一段d有 ⌊nd⌋和⌊md⌋ 不变, O(n√) 。同理枚举p,总复杂度 O(n) 。
感谢lych
#include<iostream>
#include<cstdio>
#define N 10000005
#define mo 20101009
#define ll long long
using namespace std;
ll n,m,Ans,mu[N],b[N],f[N];
void getMob()
{
mu[1]=1;
ll l=0;
for (ll i=2;i<=m;i++)
{
if (f[i]==0) mu[i]=-1,b[++l]=i;
for (ll j=1;j<=l;j++)
{
ll t=i*b[j];
if (t>m)break;
f[t]=1;
if (i%b[j]==0) {mu[t]=0;break;}
mu[t]=-mu[i];
}
}
for (ll i=1;i<=m;i++)
mu[i]=(mu[i-1]+mu[i]*i*i)%mo;
}
ll Get(ll a,ll b)
{
a=a*(1+a)/2%mo;
b=b*(1+b)/2%mo;
return a*b%mo;
}
int main()
{
scanf("%lld%lld",&n,&m);
if (n>m) swap(n,m);
getMob();
for (ll d=1,lastd;d<=n;d=lastd+1)
{
lastd=min(n/(n/d),m/(m/d));
ll sum=0,m1=m/d,n1=n/d;
for (ll p=1,lastp;p<=n1;p=lastp+1)
{
lastp=min(n1/(n1/p),m1/(m1/p));
sum+=(mu[lastp]-mu[p-1])*Get(n1/p,m1/p)%mo;
sum=sum%mo;
}
Ans=(Ans+((d+lastd)*(lastd-d+1)/2)%mo*sum%mo)%mo;
}
printf("%lld\n",(Ans%mo+mo)%mo);
return 0;
}