这题公式真tm难推……为了这题费了我一个草稿本……
woc……在51Nod上码LaTeX码了两个多小时……
一开始码完了前半段,刚码完后半段突然被51Nod吃了,重新码完后半段之后前半段又被吃了,吓得我赶紧换Notepad++接着写……
有的细节懒得再码了,这么一坨LaTeX估计也够你们看了……
\begin{align}
ans=\sum_{i=1}^n\sum_{j=1}^n [i,j]\\
=2\sum_{i=1}^n\sum_{j=1}^i [i,j]-\frac{n(n+1)}2\\
Let\space s(n)=\sum_{i=1}^n\sum_{j=1}^i [i,j],f(n)=\sum_{i=1}^n [i,n]\\
f(n)=\sum_{i=1}^n [i,n]\\
=\sum_{i=1}^n\frac{in}{(i,n)}\\
=n\sum_{i=1}^n\frac i{(i,n)}\\
=n\sum_{d|n}\sum_{i=1}^n[(i,n)=d]\frac i d\\
=n\sum_{d|n}\sum_{i=1}^{\frac n d}[(i,\frac n d)=1]i\\
=n\sum_{d|n}\sum_{i=1}^{d}[(i,d)=1]i\\
=n\sum_{d|n}\frac{\phi(d)d+[d=1]}2\\
=n\frac{1+\sum_{d|n}\phi(d)d}2\\
s(n)=\sum_{i=1}^n f(i)\\
=\frac{\sum_{i=1}^n i(1+\sum_{d|i}\phi(d)d)}2\\
=\frac{\sum_{i=1}^n i+\sum_{i=1}^n i\sum_{d|i}\phi(d)d}2\\
=\frac{\frac{n(n+1)}2+\sum_{i=1}^n i\sum_{d|i}\phi(d)d}2\\
=\frac{\frac{n(n+1)}2+\sum_{d=1}^n\phi(d)d\sum_{d|i}i}2\\
=\frac{\frac{n(n+1)}2+\sum_{d=1}^n\phi(d)d^2\sum_{i=1}^{\lfloor\frac n d\rfloor}i}2\\
=\frac{\frac{n(n+1)}2+\sum_{i=1}^n i\sum_{d=1}^{\lfloor\frac n i\rfloor}\phi(d)d^2}2\\
ans=2s(n)-\frac{n(n+1)}2\\
=\sum_{i=1}^n i\sum_{d=1}^{\lfloor\frac n i\rfloor}\phi(d)d^2\\
Let \space h(d)=\phi(d)d^2,g(n)=\sum_{d=1}^nh(d)\\
n=\sum_{d|n}\phi(d)\\
n^3=\sum_{d|n}\phi(d)n^2\\
=\sum_{d|n}\phi(d)d^2(\frac n d)^2\\
=\sum_{d|n}h(d)(\frac n d)^2\\
\sum_{i=1}^n i^3=\sum_{i=1}^n\sum_{d|i}h(d)(\frac i d)^2\\
=\sum_{d=1}^n h(d)\sum_{d|i}(\frac i d)^2\\
=\sum_{d=1}^n h(d)\sum_{i=1}^{\lfloor\frac n d \rfloor}i^2\\
=\sum_{i=1}^n i^2\sum_{d=1}^{\lfloor\frac n i\rfloor}h(d)\\
=\sum_{i=1}^n i^2 g(\lfloor\frac n i\rfloor)\\
g(n)=\sum_{i=1}^n i^3-\sum_{i=2}^ni^2 g(\lfloor\frac n i\rfloor)
\end{align}
然后就是杜教筛的形式了,上杜教筛即可
\begin{align}
\sum_{i=1}^n i^3=(\frac{n(n+1)}2)^2\\
\sum_{i=1}^n i^2=\frac{n(n+1)(2n+1}6\\
ans=\sum_{i=1}^n i g(\lfloor\frac n i\rfloor)
\end{align}
在外面套上一层分块不会影响复杂度,利用g的定义,筛出$\phi$之后即可算出较小的g,较大的g直接杜教筛算即可,总复杂度$O(n^{\frac 2 3})$
贴两份代码(虽然Python2的代码用Python2和Pypy2交都过不去......):
‘‘‘ h(i)=phi(d)*d^2 g(i)=sum{h(j)|1<=j<=i} g(n)=sum{i^3|1<=i<=n}-sum{i^2*g(n/i)|2<=i<=n} 线筛预处理一部分g,大一些的部分直接上杜教筛即可 s_3(n)=s_1(n)^2,s_2(n)=n(n+1)(2n+1)/6 ‘‘‘ p=1000000007 table_size=8000000 def get_table(n): global phi notp=[False for i in xrange(n+1)] prime=[] cnt=0 phi[1]=1 for i in xrange(2,n+1): if not notp[i]: prime.append(i) cnt+=1 phi[i]=i-1 for j in xrange(cnt): if i*prime[j]>n: break notp[i*prime[j]]=True if i%prime[j]: phi[i*prime[j]]=phi[i]*(prime[j]-1) else: phi[i*prime[j]]=phi[i]*prime[j] break for i in xrange(2,n+1): phi[i]=phi[i]*i*i%p phi[i]=(phi[i]+phi[i-1])%p def s1(n): return (n*(n+1)>>1)%p def s2(n): return (n*(n+1)*((n<<1)+1)>>1)/3%p def S(n): if n<table_size: return phi[n] elif hashmap.has_key(n): return hashmap[n] ans=n*(n+1)/2 ans*=ans ans%=p i=2 while i<=n: last=n/(n/i) #print ‘last=%d‘%last ans-=(s2(last)-s2(i-1))*S(n/i)%p ans%=p i=last+1 if ans<0: ans+=p hashmap[n]=ans return ans n=input() hashmap=dict() table_size=min(table_size,n) phi=[0 for i in xrange(table_size+1)] get_table(table_size) #print ‘table OK‘ ans=0 i=1 while i<=n: last=n/(n/i) ans+=S(n/i)*(s1(last)-s1(i-1))%p ans%=p i=last+1 print ans
#include<cstdio> #include<cstring> #include<algorithm> #include<ext/pb_ds/assoc_container.hpp> #include<ext/pb_ds/hash_policy.hpp> #define s1(n) ((long long)(n)%p*(((n)+1)%p)%p*inv_2%p) #define s2(n) ((long long)(n)%p*(((n)+1)%p)%p*((((long long)(n)%p)<<1)%p+1)%p*inv_6%p) using namespace std; using namespace __gnu_pbds; const int table_size=10000010,maxn=table_size+10,p=1000000007,inv_2=500000004,inv_6=166666668; void get_table(int); int S(long long); bool notp[maxn]={false}; int prime[maxn]={0},phi[maxn]={0}; gp_hash_table<long long,int>hashmap; long long n; int main(){ scanf("%lld",&n); get_table(min((long long)table_size,n)); int ans=0; for(long long i=1,last;i<=n;i=last+1){ last=n/(n/i); ans+=S(n/i)*((s1(last)-s1(i-1))%p)%p; ans%=p; } if(ans<0)ans+=p; printf("%d",ans); return 0; } void get_table(int n){ phi[1]=1; for(int i=2;i<=n;i++){ if(!notp[i]){ prime[++prime[0]]=i; phi[i]=i-1; } for(int j=1;j<=prime[0]&&i*prime[j]<=n;j++){ notp[i*prime[j]]=true; if(i%prime[j])phi[i*prime[j]]=phi[i]*(prime[j]-1); else{ phi[i*prime[j]]=phi[i]*prime[j]; break; } } } for(int i=2;i<=n;i++){ phi[i]=(long long)phi[i]*i%p*i%p; phi[i]=(phi[i]+phi[i-1])%p; } } int S(long long n){ if(n<=table_size)return phi[n]; else if(hashmap.find(n)!=hashmap.end())return hashmap[n]; int ans=s1(n)*s1(n)%p; for(long long i=2,last;i<=n;i=last+1){ last=n/(n/i); ans-=S(n/i)*((s2(last)-s2(i-1))%p)%p; ans%=p; } if(ans<0)ans+=p; return hashmap[n]=ans; } /* h(i)=phi(d)*d^2 g(i)=sum{h(j)|1<=j<=i} g(n)=sum{i^3|1<=i<=n}-sum{i^2*g(n/i)|2<=i<=n} ans=sum{i*g(n/i)|1<=i<=n} 线筛预处理一部分g,大一些的部分直接上杜教筛即可 s_3(n)=s_1(n)^2,s_2(n)=n(n+1)(2n+1)/6 */
噫......话说cnblogs的代码怎么突然就残了......吓得我都换了个方式才敢贴代码......
原文:http://www.cnblogs.com/hzoier/p/6272418.html