题目描述:
求∑i=1n∑j=1nσ1(i∗j)\sum_{i=1}^n\sum_{j=1}^n\sigma_1(i*j)i=1∑nj=1∑nσ1(i∗j)
n≤109,mod 109+7n\le10^9,mod ~10^9+7n≤109,mod 109+7
题目分析:
有个结论:σk(i∗j)=∑x∣i∑y∣j[(x,y)==1] xk∗jk/yk\sigma_k(i*j)=\sum_{x|i}\sum_{y|j}[(x,y)==1]~x^k*j^k/y^kσk(i∗j)=x∣i∑y∣j∑[(x,y)==1] xk∗jk/yk
记σk(n)\sigma_k(n)σk(n)为nnn的约数的kkk次幂之和,质因数分解nnn,n=p1a1p2a2...ptatn=p_1^{a_1}p_2^{a_2}...p_t^{a_t}n=p1a1p2a2...ptat
σk(n)=(1+p11k+p12k+⋯+p1a1k) ∗(1+p21k+p22k+⋯+p2a2k) … ∗(1+pt1k+pt2k+⋯+ptatk)\sigma_k(n)=(1+p_1^{1k}+p_1^{2k}+\dots+p_1^{a_1k})\\~~~~~~~~~~~*(1+p_2^{1k}+p_2^{2k}+\dots+p_2^{a_2k})\\~~~~~~~~~~~~\dots\\~~~~~~~~~~*(1+p_t^{1k}+p_t^{2k}+\dots+p_t^{a_tk})σk(n)=(1+p11k+p12k+⋯+p1a1k) ∗(1+p21k+p22k+⋯+p2a2k) … ∗(1+pt1k+pt2k+⋯+ptatk)
考虑一个质因子ppp,它对σk(n)\sigma_k(n)σk(n)的贡献为1+pk+p2k+...+pak1+p^k+p^{2k}+...+p^{ak}1+pk+p2k+...+pak
那么看σk(i∗j)\sigma_k(i*j)σk(i∗j),考虑它们的公共质因子ppp,在i中有a次,在j中有b次,造成的贡献就可以表示为∑x=0a∑y=0b[(px,py)==1] pxk∗pbk/pyk\sum_{x=0}^a\sum_{y=0}^b[(p^x,p^y)==1]~p^{xk}*p^{bk}/p^{yk}x=0∑ay=0∑b[(px,py)==1] pxk∗pbk/pyk
根据乘法原理,有σk(i∗j)=∑x1=0a1∑y1=0b1[(px1,py1)==1] px1k∗pb1k/py1k ∗∑x2=0a2∑y2=0b2[(px2,py2)==1] px2k∗pb2k/py2k… ∗∑xt=0at∑yt=0bt[(pxt,pyt)==1] pxtk∗pbtk/pytk\sigma_k(i*j)=\sum_{x_1=0}^{a_1}\sum_{y_1=0}^{b_1}[(p^{x_1},p^{y_1})==1]~p^{x_1k}*p^{b_1k}/p^{y_1k}\\~~~~~~~~~~~~~~~*
\sum_{x_2=0}^{a_2}\sum_{y_2=0}^{b_2}[(p^{x_2},p^{y_2})==1]~p^{x_2k}*p^{b_2k}/p^{y_2k}\\\dots\\
~~~~~~~~~~~~~~~*\sum_{x_t=0}^{a_t}\sum_{y_t=0}^{b_t}[(p^{x_t},p^{y_t})==1]~p^{x_tk}*p^{b_tk}/p^{y_tk}σk(i∗j)=x1=0∑a1y1=0∑b1[(px1,py1)==1] px1k∗pb1k/py1k ∗x2=0∑a2y2=0∑b2[(px2,py2)==1] px2k∗pb2k/py2k… ∗xt=0∑atyt=0∑bt[(pxt,pyt)==1] pxtk∗pbtk/pytk
只有当所有(px,py)==1(p^x,p^y)==1(px,py)==1都满足时才会对答案造成贡献,所以可变形为:
σk(i∗j)=∑x∣i∑y∣j[(x,y)==1] xk∗jk/yk\sigma_k(i*j)=\sum_{x|i}\sum_{y|j}[(x,y)==1]~x^k*j^k/y^kσk(i∗j)=x∣i∑y∣j∑[(x,y)==1] xk∗jk/yk
ok,正文开始
∑i=1n∑j=1nσ1(i∗j)=∑i=1n∑j=1n∑x∣i∑y∣j[(x,y)==1] x∗j/y=∑k=1nμ(k)∑x=1nk⌊nkx⌋∑y=1nk∑j=1nkyxk∗kyj/ky=∑k=1nμ(k)k∑x=1nk⌊nkx⌋x∑j=1nkj⌊nkj⌋=∑k=1nμ(k)k(∑x=1nk⌊nkx⌋x)2=∑k=1nμ(k)k(∑i=1nkσ1(i))2\large\begin{aligned} &\sum_{i=1}^n\sum_{j=1}^n\sigma_1(i*j)\\ &=\sum_{i=1}^n\sum_{j=1}^n\sum_{x|i}\sum_{y|j}[(x,y)==1]~x*j/y\\ &=\sum_{k=1}^n\mu(k)\sum_{x=1}^{\frac nk}\lfloor\frac n{kx}\rfloor\sum_{y=1}^{\frac nk}\sum_{j=1}^{\frac n{ky}}xk*kyj/ky\\ &=\sum_{k=1}^n\mu(k)k\sum_{x=1}^{\frac nk}\lfloor\frac n{kx}\rfloor x\sum_{j=1}^{\frac nk}j\lfloor\frac n{kj}\rfloor\\ &=\sum_{k=1}^n\mu(k)k\left(\sum_{x=1}^{\frac nk}\lfloor\frac n{kx}\rfloor x\right)^2\\ &=\sum_{k=1}^n\mu(k)k\left(\sum_{i=1}^{\frac nk}\sigma_1(i)\right)^2 \end{aligned}i=1∑nj=1∑nσ1(i∗j)=i=1∑nj=1∑nx∣i∑y∣j∑[(x,y)==1] x∗j/y=k=1∑nμ(k)x=1∑kn⌊kxn⌋y=1∑knj=1∑kynxk∗kyj/ky=k=1∑nμ(k)kx=1∑kn⌊kxn⌋xj=1∑knj⌊kjn⌋=k=1∑nμ(k)k⎝⎜⎛x=1∑kn⌊kxn⌋x⎠⎟⎞2=k=1∑nμ(k)k⎝⎜⎛i=1∑knσ1(i)⎠⎟⎞2
线性筛10610^6106,μ(k)k\mu(k)kμ(k)k标准的杜教筛,σ1(n)的前缀和可以n\sigma_1(n)的前缀和可以\sqrt nσ1(n)的前缀和可以n分块暴算
时间复杂度O(n23)O(n^{\frac 23})O(n32)
- 其实有种更简单清晰的推法,第一步先不要把x,y提到最前面
=∑i=1n∑j=1n∑x∣i∑y∣j[(x,y)==1] x∗j/y=∑k=1nμ(k)∑i=1nk∑j=1nk∑x∣i∑y∣ixk∗jk/yk=∑k=1nμ(k)k∑i=1nk∑j=1nk∑x∣ix∑y∣jjy=∑k=1nμ(k)k∑i=1nk∑j=1nkσ1(i)∗σ1(j)=∑k=1nμ(k)k(∑i=1nkσ1(i))2\begin{aligned} &=\sum_{i=1}^n\sum_{j=1}^n\sum_{x|i}\sum_{y|j}[(x,y)==1]~x*j/y\\ &=\sum_{k=1}^n\mu(k)\sum_{i=1}^{\frac nk}\sum_{j=1}^{\frac nk}\sum_{x|i}\sum_{y|i}xk*jk/yk\\ &=\sum_{k=1}^n\mu(k)k\sum_{i=1}^{\frac nk}\sum_{j=1}^{\frac nk}\sum_{x|i}x\sum_{y|j}{\frac jy}\\ &=\sum_{k=1}^n\mu(k)k\sum_{i=1}^{\frac nk}\sum_{j=1}^{\frac nk}\sigma_1(i)*\sigma_1(j)\\ &=\sum_{k=1}^n\mu(k)k\left(\sum_{i=1}^{\frac nk}\sigma_1(i)\right)^2 \end{aligned}=i=1∑nj=1∑nx∣i∑y∣j∑[(x,y)==1] x∗j/y=k=1∑nμ(k)i=1∑knj=1∑knx∣i∑y∣i∑xk∗jk/yk=k=1∑nμ(k)ki=1∑knj=1∑knx∣i∑xy∣j∑yj=k=1∑nμ(k)ki=1∑knj=1∑knσ1(i)∗σ1(j)=k=1∑nμ(k)k⎝⎛i=1∑knσ1(i)⎠⎞2
#include<cstdio>
#include<map>
using namespace std;
const int N = 1000000, mod = 1e9+7, inv2 = 5e8+4;
int p[N/10],sm[N+5],sd[N+5],mp[N+5];
bool v[N+5];
map<int,int>F;
void Prime()
{
sm[1]=sd[1]=1;int cnt=0;
for(int i=2;i<=N;i++)
{
if(!v[i]) p[++cnt]=i,sm[i]=-i,sd[i]=mp[i]=i+1;
for(int j=1,k;j<=cnt&&(k=p[j]*i)<=N;j++)
{
v[k]=1;
if(i%p[j]==0) {sm[k]=0,mp[k]=mp[i]*p[j]+1,sd[k]=sd[i]/mp[i]*mp[k];break;}
sm[k]=sm[i]*sm[p[j]];
sd[k]=sd[i]*sd[p[j]];
mp[k]=p[j]+1;
}
}
for(int i=1;i<=N;i++) sm[i]=(sm[i]+sm[i-1])%mod,sd[i]=(sd[i]+sd[i-1])%mod;
}
int Summu(int n)
{
if(n<=N) return sm[n];
if(F.count(n)) return F[n];
int ret=1;
for(int i=2,j;i<=n;i=j+1)
{
j=n/(n/i);
ret=(ret-1ll*(i+j)*(j-i+1)%mod*inv2%mod*Summu(n/i))%mod;
}
return F[n]=ret;
}
int calc(int n)
{
if(n<=N) return sd[n];
int ret=0;
for(int i=1,j;i<=n;i=j+1)
{
j=n/(n/i);
ret=(ret-1ll*(i+j)*(j-i+1)%mod*inv2%mod*(n/i))%mod;
}
return ret;
}
int main()
{
Prime();
int n,ans=0;
scanf("%d",&n);
for(int i=1,j,tmp,pre=0,tt;i<=n;i=j+1)
{
j=n/(n/i);
ans=(ans+1ll*((tmp=Summu(j))-pre)*(tt=calc(n/i))%mod*tt)%mod;
pre=tmp;
}
printf("%d",(ans+mod)%mod);
}