题解:[UVA-11426]GCD - Extreme (II)

34 篇文章 0 订阅

GCD - Extreme (II)

∑ i = 1 n ∑ j = i + 1 n gcd ⁡ ( i , j ) \sum_{i=1}^n\sum_{j=i+1}^n\gcd(i,j) i=1nj=i+1ngcd(i,j)

解法一:蓝书解法,计算贡献

f ( n ) = ∑ i = 1 n − 1 gcd ⁡ ( i , n ) f(n)=\sum_{i=1}^{n-1}\gcd(i,n) f(n)=i=1n1gcd(i,n),则所求答案为 f ( n ) f(n) f(n)的前缀和。
注意到 gcd ⁡ ( i , n ) = k \gcd(i,n)=k gcd(i,n)=k的值一定是n的约数,按照这个约数进行分类。设满足 gcd ⁡ ( x , n ) = k \gcd(x,n)=k gcd(x,n)=k的约束有g(n,i)个,则 f ( n ) = s u m { i × g ( n , i ) ∣ d m o d    i = = 0 } f(n)=sum\{i\times g(n,i)|d\mod i==0\} f(n)=sum{i×g(n,i)dmodi==0}
依次计算 f ( n ) f(n) f(n)需要枚举每个 n n n的约数 i i i,速度较慢,但是对每个 i i i枚举它的倍数 k i ki ki来更新 f ( k i ) f(ki) f(ki)的值,此时速度和普通筛法同阶。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct EulerSieve
{
	vector<int> p,m,phi;
	EulerSieve(int N):m(N,0),phi(N,0)
	{
		phi[1]=1;
		for(long long i=2,k; i<N; ++i)
		{
			if(!m[i])p.push_back(m[i]=i),phi[i]=i-1;
			for(int j=0; j<p.size()&&(k=i*p[j])<N; ++j)
			{
				phi[k]=phi[i]*p[j];
				if((m[k]=p[j])==m[i])break;
				phi[k]-=phi[i];
			}
		}
	}
};
struct GCDExtremeII:EulerSieve
{
	vector<ll> f;
	GCDExtremeII(int N):EulerSieve(N),f(N)
	{
		for(int i=1; i<N; ++i)
		{
			for(int k=2; k*i<N; ++k)
				f[k*i]+=i*phi[k];
			f[i]+=f[i-1];
		}
	}
} g(4e6+9);
int main()
{
	for(int n; ~scanf("%d",&n)&&n;)printf("%lld\n",g.f[n]);
}

解法二:分块

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct EulerSieve
{
	vector<int> p,m,phi;
	vector<ll> sum;
	EulerSieve(int N):m(N,0),phi(N,0),sum(N,0)
	{
		phi[1]=1;
		for(long long i=2,k; i<N; ++i)
		{
			if(!m[i])p.push_back(m[i]=i),phi[i]=i-1;
			for(int j=0; j<p.size()&&(k=i*p[j])<N; ++j)
			{
				phi[k]=phi[i]*p[j];
				if((m[k]=p[j])==m[i])break;
				phi[k]-=phi[i];
			}
		}
		for(int i=0; i<N; ++i)sum[i]=sum[i-1]+phi[i];
	}
} e(4e6+9);
int main()
{
	for(ll n,sum,tmp; ~scanf("%lld",&n)&&n;)
	{
		for(int i=1,j=sum=0; i<=n; i=j+1)
			tmp=n/i,sum+=tmp*tmp*(e.sum[j=n/tmp]-e.sum[i-1]);
		printf("%lld\n",(sum-(n+1)*n/2)/2);
	}
}

解法三:莫比乌斯反演

a n s = ∑ d = 1 n d ∑ i = 1 n / d μ ( i ) [ n i d ] 2 = ∑ T = 1 n [ n T ] 2 ∑ d ∣ T d μ ( T d ) ans=\sum_{d=1}^nd\sum_{i=1}^{n/d}\mu(i)[\frac{n}{id}]^2=\sum_{T=1}^n[\frac{n}{T}]^2\sum_{d|T}d\mu(\frac{T}{d}) ans=d=1ndi=1n/dμ(i)[idn]2=T=1n[Tn]2dTdμ(dT)
数论分块可 O ( n ) O(\sqrt n) O(n )查询,总时间复杂度 O ( n n ) O(n\sqrt n) O(nn )

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct EulerSieve
{
	vector<int> p,m,mu,sum;//素数序列,最小素因子,欧拉函数,莫比乌斯函数
	EulerSieve(int N):m(N,0),mu(N,0),sum(N,0)
	{
		mu[1]=1;//m[1]=0
		for(long long i=2,k; i<N; ++i)//防i*p[j]爆int
		{
			if(!m[i])p.push_back(m[i]=i),mu[i]=-1;//i是素数
			for(int j=0; j<p.size()&&(k=i*p[j])<N; ++j)
			{
				if((m[k]=p[j])==m[i])
				{
					mu[k]=0;
					break;
				}
				mu[k]=-mu[i];
			}
		}
		for(int i=1; i<N; ++i)sum[i]=sum[i-1]+mu[i];
	}
} e(4e6+9);
int main()
{
	for(ll n,sum,tmp; ~scanf("%lld",&n)&&n;)
	{
		sum=0;
		for(int i=1; i<=n; ++i)
			for(ll l=1,r,tmp,m=n/i; l<=m; l=r+1)
				tmp=m/l,sum+=i*tmp*tmp*(e.sum[r=m/tmp]-e.sum[l-1]);
		printf("%lld\n",(sum-(n+1)*n/2)/2);
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值