去年的 tangjz 非常喜欢做数论题,但是一年以后的 tangjz 却不那么会做了。
在整理以前的试题时,他发现了这样一道题目:“求
∑σ(i)
,其中
1≤i≤N
,
σ(i)
表示
i
的约数之和。”
现在他长大了,题目也变难了,所以麻烦你来帮他解决一道数论题吧。
他需要你求如下表达式的值:
∑Ni=1∑Nj=1max(i,j)⋅σ(i⋅j)
其中
max(i,j)
表示
i
和
j
里的最大值,
σ(i⋅j)
表示
i⋅j
的约数之和。
例如当
N=2
的时候,由
σ(1)=1,σ(2)=1+2=3,σ(4)=1+2+4=7
可知,答案应为
1⋅σ(1⋅1)+2⋅σ(1⋅2)+2⋅σ(2⋅1)+2⋅σ(2⋅2)=27
。
他发现答案有点大,所以你只需要告诉他答案模
1000000007
的值即可。
Input
每个测试点含有多组测试数据。 第一行是一个正整数T,表示接下来有T组测试数据。(1≤T≤50000) 接下来的T行,每组测试数据占一行。 每行有一个正整数N,含义如描述所示。(1≤N≤1000000)
Output
共有T行。对于每组测试数据,输出一行信息"Case #x: y"。 其中x表示对应的是第几组测试数据,y表示相应的答案模1000000007的值。
Input示例
5 1 2 3 4 5
Output示例
Case #1: 1 Case #2: 27 Case #3: 162 Case #4: 686 Case #5: 1741 【分析】 经过一番莫比乌斯反演,可以做到O(nlogn)预处理,O(1)查询 线性筛写的太垃圾,需要特殊的卡常技巧 代码只有一次AC过...趁评测机跑得飞快水过了
【代码】
//51nod 1584 加权约数和 #include<bits/stdc++.h> #define N 1000000 #define ll long long #define M(a) memset(a,0,sizeof a) #define fo(i,j,k) for(i=j;i<=k;i++) using namespace std; const int mxn=1000001; const int mod=1e9+7; int n,m,T; bool vis[mxn]; int s[mxn],ss[mxn],miu[mxn],pri[mxn]; int ans[mxn],g[mxn],c[mxn]; inline int read() { int x=0;char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar(); return x; } inline int ksm(int x,int k) { int b=x;--k; while(k) { if(k&1) x=(ll)x*b%mod; b=(ll)b*b%mod,k>>=1; } return x; } inline int get(int x,int p) { int cnt=0,tmp=x; while(tmp%p==0) cnt++,tmp/=p; int t=ksm(p,2*cnt+1)-1; if(!c[p-1]) c[p-1]=ksm(p-1,mod-2); t=(ll)t*c[p-1]%mod; return (ll)g[tmp]*t%mod; } inline void init() { int i,j; miu[1]=g[1]=1; fo(i,2,N) { if(!vis[i]) pri[++pri[0]]=i,miu[i]=-1,g[i]=(1+i+(ll)i*i%mod)%mod; for(int j=1;j<=pri[0] && (ll)i*pri[j]<=N;j++) { vis[i*pri[j]]=1; if(i%pri[j]==0) { g[i*pri[j]]=get(i*pri[j],pri[j]); break; } miu[i*pri[j]]=-miu[i]; g[i*pri[j]]=(ll)g[i]*g[pri[j]]%mod; } } for(i=1;i<=N;i++) for(j=i;j<=N;j+=i) { s[j]=s[j]+i; if(s[j]>mod) s[j]-=mod; } fo(i,1,N) { ss[i]=(ss[i-1]+s[i])%mod; if(ss[i]>mod) ss[i]-=mod; } for(i=1;i<=N;i++) if(miu[i]) for(j=i;j<=N;j+=i) { ans[j]=ans[j]+(ll)i*j*miu[i]%mod*s[j/i]%mod*ss[j/i]%mod; if(ans[j]<0) ans[j]+=mod; else if(ans[j]>mod) ans[j]-=mod; } fo(i,1,N) { ans[i]=ans[i]+ans[i-1]; if(ans[i]>mod) ans[i]-=mod; } fo(i,1,N) g[i]=(ll)i*g[i]%mod; fo(i,1,N) { g[i]=g[i-1]+g[i]; if(g[i]>mod) g[i]-=mod; } } int main() { init(); int i,j; T=read(); fo(i,1,T) { n=read(); printf("Case #%d: %d\n",i,(2*ans[n]%mod-g[n]+mod)%mod); } return 0; }