正题
题目链接:http://www.51nod.com/Challenge/Problem.html#problemId=1220
题目大意
给出nnn,求∑i=1n∑j=1nσ(i∗j)\sum_{i=1}^n\sum_{j=1}^n\sigma(i*j)i=1∑nj=1∑nσ(i∗j)
其中σ\sigmaσ表示约数和。
解题思路
首先有结论σ(i∗j)=∑x∣i∑y∣j[gcd(x,y)==1]xyj\sigma(i*j)=\sum_{x|i}\sum_{y|j}[gcd(x,y)==1]\frac{x}{y}jσ(i∗j)=x∣i∑y∣j∑[gcd(x,y)==1]yxj
大概是枚举两个约数的占比。
∑i=1n∑j=1n∑x∣i∑y∣i[gcd(x,y)==1]xyj\sum_{i=1}^n\sum_{j=1}^n\sum_{x|i}\sum_{y|i}[gcd(x,y)==1]\frac{x}{y}ji=1∑nj=1∑nx∣i∑y∣i∑[gcd(x,y)==1]yxj
这里就直接上反演了
∑d=1nμ(d)∑i=1n∑j=1n∑x∣i∑y∣i[d∣gcd(x,y)]xyj\sum_{d=1}^n\mu(d)\sum_{i=1}^n\sum_{j=1}^n\sum_{x|i}\sum_{y|i}[d|gcd(x,y)]\frac{x}{y}jd=1∑nμ(d)i=1∑nj=1∑nx∣i∑y∣i∑[d∣gcd(x,y)]yxj
∑d=1nμ(d)∑x∣d∑y∣dxy∑x∣i∑y∣jj\sum_{d=1}^n\mu(d)\sum_{x|d}\sum_{y|d}\frac{x}{y}\sum_{x|i}\sum_{y|j}jd=1∑nμ(d)x∣d∑y∣d∑yxx∣i∑y∣j∑j
∑d=1nμ(d)∑x∣d∑y∣dxyy(⌊ny⌋+1)⌊ny⌋⌊nx⌋2\sum_{d=1}^n\mu(d)\sum_{x|d}\sum_{y|d}\frac{x}{y}y\frac{(\lfloor\frac{n}{y}\rfloor+1)\lfloor\frac{n}{y}\rfloor\lfloor\frac{n}{x}\rfloor}{2}d=1∑nμ(d)x∣d∑y∣d∑yxy2(⌊yn⌋+1)⌊yn⌋⌊xn⌋
∑d=1nμ(d)∑x∣d⌊nx⌋x∑y∣d(⌊ny⌋+1)⌊ny⌋2\sum_{d=1}^n\mu(d)\sum_{x|d}\lfloor\frac{n}{x}\rfloor x\sum_{y|d}\frac{(\lfloor\frac{n}{y}\rfloor+1)\lfloor\frac{n}{y}\rfloor}{2}d=1∑nμ(d)x∣d∑⌊xn⌋xy∣d∑2(⌊yn⌋+1)⌊yn⌋
∑d=1nμ(d)d∑x=1⌊nd⌋⌊nxd⌋x∑y=1⌊nd⌋(⌊nyd⌋+1)⌊nyd⌋2\sum_{d=1}^n\mu(d)d\sum_{x=1}^{\lfloor\frac{n}{d}\rfloor}\lfloor\frac{n}{xd}\rfloor x\sum_{y=1}^{\lfloor\frac{n}{d}\rfloor}\frac{(\lfloor\frac{n}{yd}\rfloor+1)\lfloor\frac{n}{yd}\rfloor}{2}d=1∑nμ(d)dx=1∑⌊dn⌋⌊xdn⌋xy=1∑⌊dn⌋2(⌊ydn⌋+1)⌊ydn⌋
前面那个∑d=1nμ(d)d\sum_{d=1}^n\mu(d)d∑d=1nμ(d)d可以杜教筛来求,卷上一个ididid之后∑d∣nμ(d)∗d∗nd=n∑d∣nμ(d)\sum_{d|n}\mu(d)*d*\frac{n}{d}=n\sum_{d|n}\mu(d)∑d∣nμ(d)∗d∗dn=n∑d∣nμ(d)就是ϵ\epsilonϵ了。
考虑如何求后面那两个,第一个我们把它化简一下∑i=1n(⌊ni⌋+1)⌊ni⌋2=∑i=1ni⌊ni⌋\sum_{i=1}^{n}\frac{(\lfloor\frac{n}{i}\rfloor+1)\lfloor\frac{n}{i}\rfloor}{2}=\sum_{i=1}^{n}i\lfloor\frac{n}{i}\rfloori=1∑n2(⌊in⌋+1)⌊in⌋=i=1∑ni⌊in⌋
就和前面那个式子一样了,对于这个式子,我们可以理解为枚举每个数作为约数的次数,那么就有∑i=1ni⌊ni⌋=∑i=1nσ(i)\sum_{i=1}^ni\lfloor\frac{n}{i}\rfloor=\sum_{i=1}^n\sigma(i)i=1∑ni⌊in⌋=i=1∑nσ(i)
这样我们就可以线性筛出比较小时的答案,然后比较大的时候就直接整除分块搞就好了。
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define ll long long
using namespace std;
const ll N=2e6,P=1e9+7;
ll n,cnt,low[N],pre[N],mu[N],pri[N],s[N];
map<ll ,ll > mark;bool v[N];
void Prime(){mu[1]=s[1]=1;for(ll i=2;i<N;i++){if(!v[i])s[i]=i+1,mu[i]=-i,low[i]=i,pri[++cnt]=i;for(ll j=1;j<=cnt&&i*pri[j]<N;j++){v[i*pri[j]]=1;if(i%pri[j]==0){low[i*pri[j]]=low[i]*pri[j];s[i*pri[j]]=(s[i]*pri[j]+s[i/low[i]])%P;break;}low[i*pri[j]]=pri[j];s[i*pri[j]]=s[i]*s[pri[j]]%P;mu[i*pri[j]]=mu[i]*mu[pri[j]];}}for(ll i=1;i<N;i++)mu[i]=(mu[i]+mu[i-1])%P,s[i]=(s[i-1]+s[i])%P;return;
}
ll Get_Mu(ll n){if(n<N)return mu[n];if(mark[n])return mark[n];ll ans=1;for(ll l=2,r;l<=n;l=r+1){r=n/(n/l);ans=(ans-Get_Mu(n/l)*(r*(r+1)/2-l*(l-1)/2)%P)%P;}return mark[n]=(ans+P)%P;
}
ll Get_Sum(ll n){if(n<N)return s[n];ll ans=0;for(ll l=1,r;l<=n;l=r+1){r=n/(n/l);ans=(ans+(n/l)*(r*(r+1)/2-l*(l-1)/2)%P)%P;}return (ans+P)%P;
}
int main()
{Prime();scanf("%lld",&n);ll ans=0;for(ll l=1,r;l<=n;l=r+1){r=n/(n/l);ll tmp=Get_Sum(n/l);tmp=tmp*tmp%P;ans=(ans+(Get_Mu(r)-Get_Mu(l-1))*tmp%P)%P;}printf("%lld",(ans+P)%P);
}