题目描述
今天的数学课上,Crash 小朋友学习了最小公倍数(Least Common Multiple)。对于两个正整数 (a) 和 (b),( ext{lcm}(a,b)) 表示能同时整除 (a) 和 (b) 的最小正整数。例如,( ext{lcm}(6, 8) = 24)。
回到家后,Crash 还在想着课上学的东西,为了研究最小公倍数,他画了一张 $ n imes m$ 的表格。每个格子里写了一个数字,其中第 (i) 行第 (j) 列的那个格子里写着数为 ( ext{lcm}(i, j))。
看着这个表格,Crash 想到了很多可以思考的问题。不过他最想解决的问题却是一个十分简单的问题:这个表格中所有数的和是多少。当 (n) 和 (m) 很大时,Crash 就束手无策了,因此他找到了聪明的你用程序帮他解决这个问题。由于最终结果可能会很大,Crash 只想知道表格里所有数的和 (mod 20101009) 的值。
输入格式
输入包含一行两个整数,分别表示 (n) 和 (m)。
输出格式
输出一个正整数,表示表格中所有数的和 (mod 20101009)的值。
#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e7+5,mod=20101009;
#define ll long long
#define int long long
bool vis[N];
int mu[N],pri[N],tot,n,m;
void Mobius(){
vis[1]=mu[1]=1;
for(int i=2;i<=n;i++){
if(!vis[i])pri[++tot]=i,mu[i]=-1;
for(int j=1;j<=tot&&i*pri[j]<=n;j++){
vis[i*pri[j]]=1;
if(i%pri[j])mu[i*pri[j]]=-mu[i];
else { mu[i*pri[j]]=0; break; }
}
}
for(int i=1;i<=n;i++)mu[i]=(i*i%mod*mu[i]%mod+mu[i-1])%mod;
}
inline int ksm(int x,int y){
int res=1;
while(y){
if(y&1)res=res*x%mod;
x=x*x%mod; y>>=1;
}
return res;
}
inline ll S(int x){
return ((x+1)*x>>1)%mod;
}
inline ll sum(int n,int m){
ll ans=0;
for(int d=1,j=0;d<=min(n,m);d=j+1){
j=min(n/(n/d),m/(m/d));
ll op=(S(m/d)*S(n/d))%mod;
ans=(ans+(mu[j]-mu[d-1])%mod*op%mod+mod)%mod;
}
return ans;
}
signed main(){
cin>>n>>m;
Mobius();
ll ans=0;
for(int d=1,j=0;d<=min(n,m);d=j+1){
j=min(n/(n/d),m/(m/d));
ans=(ans+((j-d+1)*(d+j)%mod*ksm(2,mod-2)%mod)*sum(n/d,m/d)%mod)%mod;
}
cout<<ans<<endl;
}