spoj GCDEX - GCD Extreme

传送门:http://www.spoj.com/problems/GCDEX/

思路:令g(n)=ΣΣgcd(i,j)(i<=n,j<=i),再令f(n)=Σgcd(i,n)

很显然ans=g(n)-(n+1)*n/2

那么g(n)=Σf(i)(i<=n)

f(n)在上一题已证为积性函数,线筛求出,就可以在O(n)时间打出表来。

为了方便先设mindiv[i]为i的最小质因子,T[i]为i的最小质因子次数,d[i]=mindiv[i]^t[i]

具体做法:step1:当n为质数时,显然f(i)=(p-1)*1+1*p=2*p-1

step2:再考虑如何从f(p^a)推出f(p^(a+1))

由上一题的结论得f(p^a)=p^(a-1)*(pa-a+p)

f(p^(a+1))=p*(p^(a-1)*(pa+a-1))

=p*f(p^a)+p^a*(p-1)

然后就是 f[i*pri[j]]=f[i]*pri[j]+d[i]*(pri[j]-1))*f[i/d[i]];

其实如果记了d[i],t[i],f(p^(a+1))有些已经可以直接求(比如这道)....

所以上面这段step2在这题里可不做....

<pre name="code" class="cpp">#include<cstdio>
#include<cstring>
#include<algorithm>
const int N=1000000;
using namespace std;
typedef long long ll;
ll f[N+10],t[N+10],d[N+10],pri[N+10],g[N+10],ans[N+10],tot,x=1;bool isp[N+10];

void prework(){
	memset(isp,1,sizeof(isp));
	isp[1]=0,f[1]=1;
	for (int i=2;i<=N;i++){
		if (isp[i]) pri[++tot]=i,f[i]=i+i-1,d[i]=i,t[i]=1;
		for (int j=1;j<=tot&&pri[j]*i<=N;j++){
			isp[i*pri[j]]=0;
			if (i%pri[j]==0){
				f[i*pri[j]]=f[i]*pri[j]+d[i]*(pri[j]-1))*f[i/d[i]];
				t[i*pri[j]]=t[i]+1,d[i*pri[j]]=d[i]*pri[j];break;
			}
			f[i*pri[j]]=f[i]*f[pri[j]],t[i*pri[j]]=1,d[i*pri[j]]=pri[j];
		}
	}
}

int main(){
	prework();
	g[1]=f[1];for (int i=2;i<=N;i++) g[i]=g[i-1]+f[i];
	ans[1]=1;for (int i=2;i<=N;i++) ans[i]=g[i]-1ll*(i+1)*i/2;
	scanf("%lld",&x);
	while (x) printf("%lld\n",ans[x]),scanf("%lld",&x);
	return 0;
}

另一种被0.237s和谐的算法

令g(n)=ΣΣ(gcd(i,j))(i<=n,j<=n)//和上一种不一样

f(n)=(g(n)-(n+1)*n/2)/2

考虑求g(n),有公式Σphi(d)=n (d|n)

g(n)=ΣΣΣphi(d)(1<=i<=n,1<=j<=n,d|gcd(i,j))

即有Σphi(d)*ΣΣ[d|gcd(i,j)](1<=d<=n,1<=i<=n,1<=j<=n)

后面一部分显然是(n/d)^2

于是有Σphi(d)*(n/d)^2

但是回答是O(sqrt(n))的,会被TLE和谐掉


posted @ 2015-10-12 11:24  orzpps  阅读(299)  评论(0编辑  收藏  举报