作为公式恐惧症晚期患者..就继续写一发题解补救一下
题目让求
∑i=1n∑j=1mlcm(i,j)
=∑i=1n∑j=1mi∗jgcd(i,j)
可以枚举 gcd
Ans=∑d=1n∑i=1n∑j=1mi∗jd(gcd(i,j)=d)
=∑d=1n∑i=1⌊nd⌋∑j=1⌊md⌋d2∗i∗jd(gcd(i,j)=1)
=∑d=1nd∑i=1⌊nd⌋∑j=1⌊md⌋i∗j(gcd(i,j)=1)
然后只需要继续化简这个式子,反演一下
∑i=1⌊nd⌋∑j=1⌊md⌋i∗j(gcd(i,j)=1)
=∑x=1⌊nd⌋u(x)∗x2∗∑i=1⌊nd∗x⌋∑j=1⌊md∗x⌋i∗j
=∑x=1⌊nd⌋u(x)∗x2∗⌊nd∗x⌋(⌊nd∗x⌋+1)2∗⌊md∗x⌋(⌊md∗x⌋+1)2
Ans=∑d=1nd∗∑x=1⌊nd⌋u(x)∗x2∗⌊nd∗x⌋(⌊nd∗x⌋+1)2∗⌊md∗x⌋(⌊md∗x⌋+1)2
继续等价变换令 T=d∗x
Ans=∑T=1n⌊nT⌋∗(⌊nT⌋+1)2∗⌊mT⌋∗(⌊mT⌋+1)2∗∑d|Tu(d)∗d2∗Td
然后线性筛出后面的这个东西,就是分块搞一搞了。
注意不要乘爆了 longlong ..被卡跪了3发QAQ
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<set>
#include<map>
#define ll long long
#define lowbit(x) (x&(-x))
#define N 10000010
#define R 100000009
using namespace std;
int sc()
{
int i=0,f=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')i=i*10+c-'0',c=getchar();
return i*f;
}
ll f[N];
int low[N],prime[N/10],a[N];
void pre()
{
int top=0;
f[1]=low[1]=1;
for(int i=2;i<N;i++)
{
if(!a[i])
{
low[i]=prime[++top]=i;
f[i]=(1-i)%R;
}
for(int j=1;prime[j]*i<N;j++)
{
a[i*prime[j]]=1;
if(i%prime[j]==0)
{
low[i*prime[j]]=low[i]*prime[j];
if(low[i]==i)
f[i*prime[j]]=f[i];
else
f[i*prime[j]]=f[prime[j]*low[i]]*f[i/low[i]]%R;
break;
}
low[i*prime[j]]=prime[j];
f[i*prime[j]]=f[i]*f[prime[j]]%R;
}
}
for(int i=2;i<N;i++)f[i]=(f[i-1]+(ll)i*f[i])%R;
}
int main()
{
pre();
int T=sc();
while(T--)
{
int n=sc(),m=sc();ll ans=0,t1,t2;
if(n>m)swap(n,m);
for(int i=1,last;i<=n;i=last+1)
{
last=min(n/(n/i),m/(m/i));
t1=(ll)(n/i+1)*(n/i)/2%R;
t2=(ll)(m/i+1)*(m/i)/2%R;
ans=(ans+(t1*t2%R)*(f[last]-f[i-1]))%R;
}
printf("%lld\n",(ans+R)%R);
}
return 0;
}