版权声明:原来这里可以拿来卖萌ヽ(・∀・)ノ https://blog.csdn.net/u012345506/article/details/86292618
本来想用:
i=1∑nj=1∑iiσ(ij)=i=1∑nik=1∑i2k⌊(i,k)ki⌋
来推的,结果没推出来,之后可能会再尝试推一下。
但是从上面这个式子的来历来分析,对于任意的数
k,
i对其作为
ij的因数的贡献只有
(i,k),剩余的部分必须由
j承担,换言之,若一个数
k是
ij的因数,则必然满足
(i,k)k∣j,于是我们尝试枚举
(i,k)i和
(i,k)k,当然,实际上他们分别是
i和
j的因数,于是便有了一个更加方便的公式:
σ(ij)=a∣i∑b∣j∑[(a,b)=1]abj
进入推导:
i=1∑nj=1∑iiσ(ij)=i=1∑nj=1∑iia∣i∑b∣j∑[(a,b)=1]ab=x=1∑nμ(x)i=1∑⌊xn⌋j=1∑ix2ia∣i∑aσ(j)=x=1∑nx2μ(x)i=1∑⌊xn⌋ia∣i∑j=1∑iσ(j)=x=1∑nx2μ(x)i=1∑⌊xn⌋iσs2(i)a∣i∑1=x=1∑nx2μ(x)i=1∑⌊xn⌋iσs2(i)σ(i)
容易想到通过递推来预处理所有的值,因为当
⌊in+1⌋变化时,当且仅当
i∣n+1,设:
f(n)=i=1∑nj=1∑iiσ(ij)=f(n−1)+d∣n∑d2μ(d)(di)σs2(di)σ(di)
这使得我们可以在
O(nlgon)下预处理出所有答案。
当然,为了求出正确解,还需要计算
∑i=1niσ(i2)的值,因为很简单所以就不写了。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<climits>
#include<cstdio>
#include<cmath>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
//--Container
//--
typedef long long ll;
const ll md=1e9+7;const int up=1e6;
int ct=0,mu[up+10],pr[up+10],pn,ms[up+10];ll mss[up+10],rs[up+10];bool bd[up+10];
void _init(){
int i,j,k,d,t;for(pn=0,i=2;i<=up;++i){
if(!bd[i])pr[++pn]=i,mu[i]=-1;
for(j=1;j<=pn&&(ll)pr[j]*i<=up;++j){
bd[pr[j]*i]=1,mu[pr[j]*i]=-mu[i];
if(!(i%pr[j])){mu[pr[j]*i]=0;break;}
}
}
for(i=1;i<=up;++i)for(j=i;j<=up;j+=i)ms[j]+=i;
for(mu[1]=1,i=2;i<=up;++i)mu[i]=mu[i]<0?mu[i]+md:mu[i];
for(i=1;i<=up;++i)mss[i]=(mss[i-1]+ms[i])%md;
for(i=1;i<=up;++i)for(j=i;j<=up;j+=i){
t=j/i;rs[j]=(rs[j]+(ll)i*i%md*mu[i]%md*t%md*ms[t]%md*mss[t]%md*2)%md;
rs[j]=(rs[j]+md-(ll)i*i%md*mu[i]%md*(t)%md*ms[t]%md*ms[t]%md)%md;
}
for(i=2;i<=up;++i)rs[i]=(rs[i-1]+rs[i])%md;
};
void cl(){
int n;scanf("%d",&n);printf("Case #%d: %lld\n",++ct,rs[n]);
};
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int t;scanf("%d",&t);for(_init();t--;cl());
return 0;
};