Description
今天的数学课上,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的值。
Input
输入的第一行包含两个正整数,分别表示N和M。
Output
输出一个正整数,表示表格中所有数的和mod 20101009的值。
Sample Input
Sample Output
【数据规模和约定】
100%的数据满足N, M ≤ 107。
1 #include<cstring> 2 #include<cmath> 3 #include<iostream> 4 #include<algorithm> 5 #include<cstdio> 6 7 #define ll long long 8 #define N 10000007 9 #define mod 20101009 10 using namespace std; 11 inline int read() 12 { 13 int x=0,f=1;char ch=getchar(); 14 while(ch<‘0‘||ch>‘9‘){if (ch==‘-‘) f=-1;ch=getchar();} 15 while(ch>=‘0‘&&ch<=‘9‘){x=(x<<3)+(x<<1)+ch-‘0‘;ch=getchar();} 16 return x*f; 17 } 18 19 ll n,m,ans; 20 ll sm[N]; 21 int tot,mu[N],pri[N]; 22 bool flag[N]; 23 24 ll sum(ll x,ll y) 25 { 26 return ((x*(x+1)/2)%mod)*((y*(y+1)/2)%mod)%mod; 27 } 28 void init_mu() 29 { 30 mu[1]=1; 31 for (int i=2;i<=min(n,m);i++) 32 { 33 if (!flag[i])pri[++tot]=i,mu[i]=-1; 34 for (int j=1;j<=tot&&(ll)pri[j]*i<=min(n,m);j++) 35 { 36 flag[pri[j]*i]=1,mu[pri[j]*i]=-mu[i]; 37 if (i%pri[j]==0){mu[pri[j]*i]=0;break;} 38 } 39 } 40 for (ll i=1;i<=min(n,m);i++) 41 sm[i]=(sm[i-1]+(i*i*mu[i])%mod)%mod; 42 } 43 ll F(ll x,ll y) 44 { 45 ll ans=0,ps; 46 for (ll i=1;i<=min(x,y);i=ps+1) 47 { 48 ps=min(x/(x/i),y/(y/i)); 49 ans=(ans+(sm[ps]-sm[i-1])%mod*sum(x/i,y/i)%mod)%mod; 50 } 51 return ans; 52 } 53 int main() 54 { 55 n=read(),m=read(); 56 init_mu(); 57 ll ps=0; 58 for (ll i=1;i<=min(n,m);i=ps+1) 59 { 60 ps=min(n/(n/i),m/(m/i)); 61 ans=(ans+(i+ps)*(ps-i+1)/2%mod*F(n/i,m/i)%mod)%mod; 62 } 63 ans=(ans%mod+mod)%mod; 64 printf("%lld\n",ans); 65 }
题目大意就是求∑ni=1∑mj=1lcm(i,j).
分析:
枚举d=gcd(i,j),
显然可以得到
即算出除以d后互质的对数,两个数都乘d的乘积就得到了两个数的乘积,在除以d就是他们的最小公倍数。
那怎么求f呢
令
所以