基准时间限制:8 秒 空间限制:262144 KB 分值: 640 难度:8级算法题
出一个数N,输出小于等于N的所有数,两两之间的最小公倍数之和。
相当于计算这段程序(程序中的lcm(i,j)表示i与j的最小公倍数):
由于结果很大,输出Mod 1000000007的结果。
G=0;
for(i=1;i<=N;i++)
for(j=1;j<=N;j++)
{
G = (G + lcm(i,j)) % 1000000007;
}
Input
输入一个数N。(2 <= N <= 10^10)
Output
输出G Mod 1000000007的结果。
Input示例
4
Output示例
72
之前推过一个差不多的,但是那个的数量级是10的5次的,而且不是正方形,是给出的n和m,牵扯上了莫比乌斯函数的,但是这个就不能这样搞了,反正先推一推吧。
所以:
推导部分就到这了,现在就是递归分块求了。
代码:
#include
#include
#include
#include
#include
#include
#define maxx 5000000
#define mod 1000000007
#define ll long long
using namespace std;
bool isP[maxx];
int prime[400000];
int cnt;
int phi[maxx];
ll F[maxx];
ll inv2=500000004,inv4=250000002,inv6=166666668;
ll get(ll x)
{
x%=mod;
return (x+1)*x%mod*(2*x+1)%mod*inv6%mod;
}
void init()
{
phi[1]=1;
for(int i=2;iif(!isP[i]){prime[cnt++]=i;phi[i]=i-1;}
for(int j=0;j*prime[j]*prime[j]]=true;
if(i%prime[j])
phi[i*prime[j]]=phi[i]*(prime[j]-1);
else
{
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
}
}
for(ll i=1;i*i%mod*phi[i]%mod;
for(int i=1;i1])%mod;
}
mapM;
ll work(ll x)
{
if(xreturn F[x];
if(M[x])return M[x];
ll t=x%mod;
ll ans=t*t%mod*(t+1)%mod*(t+1)%mod*inv4%mod;
for(ll i=2,last;i<=x;i=last+1)
{
last=x/(x/i);
ans=(ans-(get(last)-get(i-1))*work(x/i)%mod)%mod;
}
if(ans<0)ans=(ans+mod)%mod;
M[x]=ans;
return ans;
}
ll _get(ll a,ll b)
{
return (b-a+1)%mod*((a+b)%mod)%mod*inv2%mod;
}
int main()
{
init();
//cout<>n;
ll ans=0;
for(ll i=1,last;i<=n;i=last+1)
{
last=n/(n/i);
ans=(ans+_get(i,last)*work(n/i)%mod)%mod;
}
cout<return 0;
}