题目传送门
分析:
开始玩一个小小的trick
我们发现\(f(n)=\sum_{d|n}\mu(d)\cdot d\)是一个积性函数
所以:
\(~~~~f(n)=\prod f(p_i^{a_i})\)
\(~~~~f(gcd(x,y))\cdot f(lcm(x,y))=\prod f(p_i^{min(a_i,b_i)})\cdot f(p_i^{max(a_i,b_i)})\)
可以疯狂使用交换律然后。。。
\(~~~~\prod f(p_i^{min(a_i,b_i)})\cdot f(p_i^{max(a_i,b_i)})=f(x)\cdot f(y)\)
接下来就好办了,大力推:
\(~~~~\sum_{i=1}^{n}\sum_{j=1}^{n}f(gcd(i,j))\cdot f(lcm(i,j))\)
\(=\sum_{i=1}^{n}\sum_{j=1}^{n}f(i)\cdot f(j)\)
\(=(\sum_{i=1}^{n}f(i))^2\)
我们求里面的:
\(~~~~\sum_{i=1}^{n}\sum_{d|i}\mu(d)\cdot d\)
\(=\sum_{d=1}^{n}\mu(d)\cdot d\cdot \lfloor\frac{n}{d}\rfloor\)
分块处理\(\lfloor\frac{n}{d}\rfloor\)
后面的老套路,卷一个\(Id\)
\(~~~~\sum_{i=1}^{n}\sum_{d|i}\mu(d)\cdot d\cdot \frac{i}{d}=\sum_{i=1}^{n}i\sum_{d|i}\mu(d)=1\)
\(=\sum_{d=1}^{n}d\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\mu(i)\cdot i\)
把\(d=1\)提出来:
\(~~~~\sum_{i=1}^{n}\mu(i)\cdot i=1-\sum_{d=2}^{n}d\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\mu(i)\cdot i\)$
\(~~~~S(n)=1-\sum_{d=2}^{n}d\cdot S(\lfloor\frac{n}{d}\rfloor)\)
然后杜教筛就好了
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<iostream>
#include<map>
#include<string>
#define maxn 100005
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define inv2 500000004
using namespace std;
inline long long getint()
{
long long num=0,flag=1;char c;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
return num*flag;
}
long long N;
long long pri[maxn],cnt,np[maxn],mu[maxn];
long long ans;
map<long long,long long>M;
inline void init()
{
mu[1]=1;
for(int i=2;i<maxn;i++)
{
if(!np[i])pri[++cnt]=i,mu[i]=-1;
for(int j=1;j<=cnt&&i*pri[j]<maxn;j++)
{
np[i*pri[j]]=1;
if(i%pri[j]==0)break;
mu[i*pri[j]]=-mu[i];
}
}
for(int i=1;i<maxn;i++)(mu[i]*=i)%=MOD;
for(int i=1;i<maxn;i++)(mu[i]+=mu[i-1])%=MOD;
}
inline long long getans(long long x)
{
if(x<maxn)return mu[x];
if(M.count(x))return M[x];
long long num=1;
for(long long i=2,j;i<=x;i=j+1)
{
j=x/(x/i);
(num+=MOD-(i+j)*(j-i+1)%MOD*inv2%MOD*getans(x/i))%=MOD;
}
return M[x]=num;
}
int main()
{
N=getint();
init();
for(long long i=1,j;i<=N;i=j+1)
{
j=N/(N/i);
(ans+=(N/i)*(getans(j)-getans(i-1)))%=MOD;
}
printf("%lld\n",(ans*ans%MOD+MOD)%MOD);
}