由于不想码推导过程,粘一个by Liu Junhao
最开始推到最后的式子,却傻傻的没有意识到可以分块加速,还以为自己推错了。。=_= 表示以后看到向下取整的东东要注意了。
注意:Mod要写就写完,不要懒,谁知道会不会爆??。
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 10000000
#define MAXP 700000
#define Mod 20101009LL
int n,m,mu[MAXN+10],prime[MAXP+10],cntpr;
bool isprime[MAXN+10];
long long sum[MAXN+10];
void GetMobius(int n)
{
mu[1]=1;
for(int i=2;i<=n;i++){
if(!isprime[i]){
prime[++cntpr]=i;
mu[i]=-1;
}
for(int j=1;prime[j]*i<=n&&j<=cntpr;j++){
isprime[prime[j]*i]=true;
if(i%prime[j]==0){
mu[prime[j]*i]=0;
break;
}
mu[prime[j]*i]=-mu[i];
}
}
for(int i=1;i<=n;i++)
sum[i]=(1LL*mu[i]*i*i%Mod+sum[i-1])%Mod;
}
long long Cal(int n)
{
return 1LL*(n+1)*n/2%Mod;
}
long long F(int x,int y)
{
long long ret=0;
int side=min(x,y),last;
for(int t=1;t<=side;t=last+1){
last=min(x/(x/t),y /(y /t));
ret=(ret+((sum[last]-sum[t-1])*(Cal(x/t)*Cal(y /t)%Mod))%Mod)%Mod;
}
return ret;
}
int main()
{
scanf("%d%d",&n,&m);
GetMobius(max(n,m));
int side=min(n,m),last;
long long ans=0;
for(int i=1;i<=side;i=last+1){
last=min(n/(n/i),m /(m / i));
ans=(ans+1LL*(last+i)*(last-i+1)/2%Mod*F(n/i,m / i)%Mod)%Mod;
}
printf("%lld\n",(ans+Mod)%Mod);
}