题目
求Σni=1Σnj=1σ1(ij)Σi=1nΣj=1nσ1(ij),
其中,σ1(n)=Σd|nd,n≤109σ1(n)=Σd|nd,n≤109
解题思路
错误的结论:Ans=Σni=1Σnj=1Σa|iΣb|j[gcd(a,b)=1]abAns=Σi=1nΣj=1nΣa|iΣb|j[gcd(a,b)=1]ab。
正确的结论:Ans=Σni=1Σnj=1Σa|iΣb|j[gcd(a,b)=1]ajbAns=Σi=1nΣj=1nΣa|iΣb|j[gcd(a,b)=1]ajb。
为什么这才是对的?
打表,得出ijij的每个因子出现了一次或多次。
那么这些出现了多次的因子为什么会出现多次呢?
看下面的式子。
a1jb1=a2jb2即a1b2=a2b1a1jb1=a2jb2即a1b2=a2b1
不妨设a2>a1a2>a1,则a2=k∗a1,k>1,k∈Za2=k∗a1,k>1,k∈Z,推出b2=k∗b1b2=k∗b1。
这相当于将jb1jb1中的因数kk给了。
原式可以变成
a1jb1=a1j∗kb1∗ka1jb1=a1j∗kb1∗k
即这是一个约分的过程。
则等式右边说明k|gcd(a2,b2)k|gcd(a2,b2)。
证毕。
大神Drin_E说,先考虑每个a,ba,b对答案的贡献,最后才划开[gcd(a,b)=1][gcd(a,b)=1]部分。
所以,原式变成了Σna=1Σnb=1[gcd(a,b)=1]a∗⌊na⌋∗S(⌊nb⌋)Σa=1nΣb=1n[gcd(a,b)=1]a∗⌊na⌋∗S(⌊nb⌋)
考虑每个aa为答案贡献了多少。
相当于固定了一个值,看其余值的变化规律。
当一个确定的时候,j=b,2b,...,⌊nb⌋∗bj=b,2b,...,⌊nb⌋∗b。所以要乘上S(⌊nb⌋)S(⌊nb⌋)。
对于每一个aa,在原来的两重循环中共出现了,⌊na⌋,⌊na⌋次。
现在再划开式子[gcd(a,b)=1][gcd(a,b)=1]。
则原式为:Σna=1a∗⌊na⌋Σnb=1∗S(⌊nb⌋)Σx|gcd(a,b)μ(x)Σa=1na∗⌊na⌋Σb=1n∗S(⌊nb⌋)Σx|gcd(a,b)μ(x)
=Σnx=1μ(x)Σ⌊nx⌋a=1ax∗⌊⌊nx⌋a⌋Σ⌊nx⌋b=1S(⌊⌊nx⌋b⌋)=Σx=1nμ(x)Σa=1⌊nx⌋ax∗⌊⌊nx⌋a⌋Σb=1⌊nx⌋S(⌊⌊nx⌋b⌋)
又Σni=1i∗⌊ni⌋=Σni=1S(⌊ni⌋)Σi=1ni∗⌊ni⌋=Σi=1nS(⌊ni⌋)
所以直接杜教筛搞一下就OK了。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 1000010
#define LL long long
#define mo 1000000007
#define inv2 500000004
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
LL i,j,k,l,n,m,ans,ny;
LL mu[N],pri[N];
LL md[N],smi[N];
bool bz[N];
void pre(){
LL i,j;
mu[1]=smi[1]=1;
fo(i,2,N-10){
if(!bz[i]){
pri[++pri[0]]=i;
mu[i]=-1;
}
for(j=1;j<=pri[0]&&i*pri[j]<=N-10;j++){
if(i*pri[j]>N-10)break;
bz[i*pri[j]]=1;
if(i%pri[j]==0)break;
mu[i*pri[j]]=-mu[i];
}
}
fo(i,2,N-10){
smi[i]=smi[i-1]+i*mu[i];
smi[i]=smi[i]<0?smi[i]+mo:smi[i];
smi[i]=smi[i]>0?smi[i]-mo:smi[i];
}
}
LL Sum(LL l,LL r){
return ((r-l+1)*(r+l)%mo)*inv2%mo;
}
LL djs(LL x){
if(x<=N-10)return smi[x];
if(md[n/x])return md[n/x];
LL rs=1,i;
for(i=2;i<=x;i=x/(x/i)+1)
rs=(rs-Sum(i,x/(x/i))*djs(x/i)%mo+mo)%mo;
return md[n/x]=rs;
}
LL getS(LL x){
LL i,rs=0;
for(i=1;i*i<=x;i++)rs=(rs+i*(x/i))%mo;
for(;i<=x;i=x/(x/i)+1)
rs=(rs+Sum(i,x/(x/i))*(x/i)%mo)%mo;
return (rs*rs)%mo;
}
int main(){
freopen("1220.in","r",stdin);
scanf("%lld",&n);
pre();
ans=0;
for(i=1;i<=n;i=n/(n/i)+1){
k=(djs(n/(n/i))-djs(i-1)+mo)%mo;
ans=(ans+k*getS(n/i))%mo;
}
printf("%lld",ans);
return 0;
}