题目描述
今天的数学课上,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只想知道表格里所有数的和mod20101009的值。
输入输出格式
输入格式:
输入的第一行包含两个正整数,分别表示N和M。
输出格式:
输出一个正整数,表示表格中所有数的和mod20101009的值。
输入输出样例
输入样例#1: 复制
4 5
输出样例#1: 复制
122
说明
30%的数据满足N, M≤ 10^3。
70%的数据满足N, M≤ 10^5。
100%的数据满足N, M≤ 10^7。
分析:洛谷题解里有的,讲得挺详细。
注意:反演时设的f[x]和g[x]要把所有与[gcd(i,j)==d]的相关项全设进去,比如这题的
f[x]=i*j*[gcd(i,j)==d]
g[x]=i*j*[x|gcd(i,j)]
于是就是f[x]=mul[x]*g[n/x]
在dalao指点下终于知道g怎么求了
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#define LL long long
const LL mod=20101009;
const LL maxn=10000007;
using namespace std;
LL ans;
LL not_prime[maxn],prime[maxn];
LL mul[maxn];
LL n,m,cnt;
void getmul(LL n)
{
mul[1]=1;
for (LL i=2;i<=n;i++)
{
if (!not_prime[i])
{
prime[++cnt]=i;
mul[i]=-1;
}
for (LL j=1;j<=cnt;j++)
{
if (i*prime[j]>n) break;
not_prime[i*prime[j]]=1;
if (i%prime[j]==0)
{
mul[i*prime[j]]=0;
break;
}
mul[i*prime[j]]=-mul[i];
}
}
for (LL i=1;i<=n;i++) mul[i]=(mul[i-1]+(mul[i]*i*i)%mod)%mod;
}
LL getsum(LL l,LL r)
{
return (l+r)*(r-l+1)%mod*10050505%mod;
}
LL g(int n,int m)
{
if (n>m) swap(n,m);
LL ans=0,last=0;
for (LL i=1;i<=n;i=last+1)
{
last=min(n/(n/i),m/(m/i));
ans=(ans+getsum(1,n/i)*getsum(1,m/i)%mod*(mul[last]-mul[i-1]+mod)%mod)%mod;
}
return ans;
}
int main()
{
getmul(maxn);
scanf("%lld%lld",&n,&m);
if (n>m) swap(n,m);
for (LL i=1,last=0;i<=n;i=last+1)
{
last=min(n/(n/i),m/(m/i));
ans=(ans+getsum(i,last)*g(n/i,m/i)%mod)%mod;
}
printf("%lld",ans);
}