首页 > 其他 > 详细

51Nod 最小公倍数之和V3

时间:2017-01-11 10:12:49      阅读:331      评论:0      收藏:0      [点我收藏+]

这题公式真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的代码怎么突然就残了......吓得我都换了个方式才敢贴代码......

51Nod 最小公倍数之和V3

原文:http://www.cnblogs.com/hzoier/p/6272418.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!