今天的数学课上,Crash小朋友学习了最小公倍数(Least Common Multiple)。对于两个正整数a和b,LCM(a, b)表示能同时被a和b整除的最小正整数。例如,LCM(6, 8) = 24。回到家后,Crash还在想着课上学的东西,为了研究最小公倍数,他画了一张N*M的表格。每个格子里写了一个数字,其中第i行第j列的那个格子里写着数为LCM(i, j)。一个4*5的表格如下: 1 2 3 4 5 2 2 6 4 10 3 6 3 12 15 4 4 12 4 20 看着这个表格,Crash想到了很多可以思考的问题。不过他最想解决的问题却是一个十分简单的问题:这个表格中所有数的和是多少。当N和M很大时,Crash就束手无策了,因此他找到了聪明的你用程序帮他解决这个问题。由于最终结果可能会很大,Crash只想知道表格里所有数的和mod 20101009的值。
输出一个正整数,表示表格中所有数的和mod 20101009的值。
1 /*by SilverN*/
2 #include<algorithm>
3 #include<iostream>
4 #include<cstring>
5 #include<cstdio>
6 #include<cmath>
7 #include<vector>
8 #define LL long long
9 using namespace std;
10 const LL inv2=10050505;
11 const LL mod=20101009;
12 const int mxn=10000010;
13 int pri[mxn],cnt=0;
14 int mu[mxn];
15 LL smm[mxn];
16 bool vis[mxn];
17 void init(){
18 mu[1]=1;
19 for(int i=2;i<mxn;i++){
20 if(!vis[i]){
21 pri[++cnt]=i;
22 mu[i]=-1;
23 }
24 for(int j=1;j<=cnt && (LL)pri[j]*i<mxn;j++){
25 vis[i*pri[j]]=1;
26 if(i%pri[j]==0){mu[i*pri[j]]=0;break;}
27 mu[i*pri[j]]=-mu[i];
28 }
29 }
30 for(int i=1;i<mxn;i++)smm[i]=(smm[i-1]+(LL)i*mu[i]*i)%mod;
31 return;
32 }
33 int SUM(int x,int y){
34 return ((LL)x*(x+1)%mod*inv2%mod)*((LL)y*(y+1)%mod*inv2%mod)%mod;
35 }
36 inline int s1(int x){return (x*(x+1)%mod*inv2%mod);}
37 LL calc(int a,int b){
38 LL res=0;int pos;
39 if(a>b)swap(a,b);
40 for(int i=1;i<=a;i=pos+1){
41 int x=a/i,y=b/i;
42 pos=min(a/x,b/y);
43 res+=(smm[pos]-smm[i-1])*SUM(x,y);
44 res%=mod;
45 }
46 return res;
47 }
48 int solve(int a,int b){
49 LL res=0;int pos;
50 if(a>b)swap(a,b);
51 for(int i=1;i<=a;i=pos+1){
52 int x=a/i,y=b/i;
53 pos=min(a/x,b/y);
54 (res+=(s1(pos)-s1(i-1))*calc(x,y))%=mod;
55 }
56 return res;
57 }
58 LL n,m;
59 int main(){
60 int i,j;
61 init();
62 cin>>n>>m;
63 printf("%d\n",solve(n,m));
64 return 0;
65 }