《GMOJ-Senior-4496 【GDSOI 2016 第一题】互补约数》题解

题目大意

给出一个正整数 n n n,求 ∑ i = 1 n ∑ j ∣ i gcd ⁡ ( j , i j ) \sum_{i=1}^n\sum_{j|i}\gcd(j,\dfrac{i}{j}) i=1njigcd(j,ji)
对于 20 % 20\% 20%的数据, n ≤ 1 0 5 n \leq 10^5 n105
对于 50 % 50\% 50%的数据, n ≤ 1 0 7 n \leq 10^7 n107
对于 80 % 80\% 80%的数据, n ≤ 1 0 10 n \leq 10^{10} n1010
对于 100 % 100\% 100%的数据, n ≤ 1 0 11 n \leq 10^{11} n1011

分析

这是一道数论题。题目中给出的式子不好直接算,于是我们要化简它。

化简式子

k = i j k=\dfrac{i}{j} k=ji,并先枚举 k k k,再枚举 j j j,则 原 式 = ∑ k = 1 ∑ j = 1 gcd ⁡ ( j , k ) [ j k ≤ n ] 原式=\sum_{k=1}\sum_{j=1}\gcd(j,k)[jk \leq n] =k=1j=1gcd(j,k)[jkn]
因为要满足 j k ≤ n jk \leq n jkn,所以 k ≤ n k \leq n kn j ≤ ⌊ n k ⌋ j \leq \lfloor \dfrac{n}{k} \rfloor jkn,即 原 式 = ∑ k = 1 n ∑ j = 1 ⌊ n k ⌋ gcd ⁡ ( j , k ) 原式=\sum_{k=1}^{n}\sum_{j=1}^{\lfloor \frac{n}{k} \rfloor}\gcd(j,k) =k=1nj=1kngcd(j,k)
考虑枚举 gcd ⁡ \gcd gcd函数的值,因为对于乘积小于等于 n n n的两正整数的最大公约数小于等于 n \sqrt{n} n ,所以有 原 式 = ∑ i = 1 ⌊ n ⌋ i ∑ k = 1 n ∑ j = 1 ⌊ n k ⌋ [ gcd ⁡ ( j , k ) = i ] 原式=\sum_{i=1}^{\lfloor \sqrt{n} \rfloor}i\sum_{k=1}^n\sum_{j=1}^{\lfloor \frac{n}{k} \rfloor}[\gcd(j,k)=i] =i=1n ik=1nj=1kn[gcd(j,k)=i]
j ′ = j i j'=\dfrac{j}{i} j=ij k ′ = k i k'=\dfrac{k}{i} k=ik,则 原 式 = ∑ i = 1 ⌊ n ⌋ i ∑ k ′ = 1 ⌊ n i ⌋ ∑ j ′ = 1 ⌊ n i 2 k ′ ⌋ [ gcd ⁡ ( j ′ , k ′ ) = 1 ] 原式=\sum_{i=1}^{\lfloor \sqrt{n} \rfloor}i\sum_{k'=1}^{\lfloor \frac{n}{i} \rfloor}\sum_{j'=1}^{\lfloor \frac{n}{i^2k'} \rfloor}[\gcd(j',k')=1] =i=1n ik=1inj=1i2kn[gcd(j,k)=1]
因为 ∑ d ∣ n μ ( d ) = [ n = 1 ] \sum_{d|n}\mu(d)=[n=1] dnμ(d)=[n=1],所以 原 式 = ∑ i = 1 ⌊ n ⌋ i ∑ k ′ = 1 ⌊ n i ⌋ ∑ j ′ = 1 ⌊ n i 2 k ′ ⌋ ∑ d ∣ gcd ⁡ ( j ′ , k ′ ) μ ( d ) 原式=\sum_{i=1}^{\lfloor \sqrt{n} \rfloor}i\sum_{k'=1}^{\lfloor \frac{n}{i} \rfloor}\sum_{j'=1}^{\lfloor \frac{n}{i^2k'} \rfloor}\sum_{d|\gcd(j',k')}\mu(d) =i=1n ik=1inj=1i2kndgcd(j,k)μ(d)
改为依次枚举 d , j ′ , k ′ d,j',k' d,j,k,有 原 式 = ∑ i = 1 ⌊ n ⌋ i ∑ d = 1 μ ( d ) ∑ d ∣ j ′ ⌊ n i ⌋ ∑ d ∣ k ′ ⌊ n i 2 j ′ ⌋ 1 = ∑ i = 1 ⌊ n ⌋ i ∑ d = 1 μ ( d ) ∑ d ∣ j ′ ⌊ n i ⌋ ⌊ n i 2 j ′ d ⌋ 原式=\sum_{i=1}^{\lfloor \sqrt{n} \rfloor}i\sum_{d=1}\mu(d)\sum_{d|j'}^{\lfloor \frac{n}{i} \rfloor}\sum_{d|k'}^{\lfloor \frac{n}{i^2j'} \rfloor}1=\sum_{i=1}^{\lfloor \sqrt{n} \rfloor}i\sum_{d=1}\mu(d)\sum_{d|j'}^{\lfloor \frac{n}{i} \rfloor}\lfloor \frac{n}{i^2j'd} \rfloor =i=1n id=1μ(d)djindki2jn1=i=1n id=1μ(d)djini2jdn
a = j ′ d a=\dfrac{j'}{d} a=dj,则有 原 式 = ∑ i = 1 ⌊ n ⌋ i ∑ d = 1 μ ( d ) ∑ a = 1 ⌊ n d i ⌋ ⌊ n a d 2 i 2 ⌋ 原式=\sum_{i=1}^{\lfloor \sqrt{n} \rfloor}i\sum_{d=1}\mu(d)\sum_{a=1}^{\lfloor \frac{n}{di} \rfloor}\lfloor \frac{n}{ad^2i^2} \rfloor =i=1n id=1μ(d)a=1dinad2i2n
T = d i T=di T=di,并改为依次枚举 i , T i,T i,T,则 原 式 = ∑ i = 1 ⌊ n ⌋ i ∑ i ∣ T μ ( T i ) ∑ a = 1 ⌊ n T ⌋ ⌊ n T 2 a ⌋ 原式=\sum_{i=1}^{\lfloor \sqrt{n} \rfloor}i\sum_{i|T}\mu(\frac{T}{i})\sum_{a=1}^{\lfloor \frac{n}{T} \rfloor}\lfloor \frac{n}{T^2a} \rfloor =i=1n iiTμ(iT)a=1TnT2an
改变 i , T i,T i,T的枚举顺序,则 原 式 = ∑ T = 1 ∑ i ∣ T μ ( T i ) i ∑ a = 1 ⌊ n T ⌋ ⌊ n T 2 a ⌋ 原式=\sum_{T=1}\sum_{i|T}\mu(\frac{T}{i})i\sum_{a=1}^{\lfloor \frac{n}{T} \rfloor}\lfloor \frac{n}{T^2a} \rfloor =T=1iTμ(iT)ia=1TnT2an
因为 ∑ d ∣ n μ ( n d ) d = ϕ ( n ) \sum_{d|n}\mu(\frac{n}{d})d=\phi(n) dnμ(dn)d=ϕ(n),所以 原 式 = ∑ T = 1 ϕ ( T ) ∑ a = 1 ⌊ n T ⌋ ⌊ n T 2 a ⌋ 原式=\sum_{T=1}\phi(T)\sum_{a=1}^{\lfloor \frac{n}{T} \rfloor}\lfloor \frac{n}{T^2a} \rfloor =T=1ϕ(T)a=1TnT2an
因为当 ⌊ n T 2 a ⌋ ≥ 1 \lfloor \frac{n}{T^2a} \rfloor \geq 1 T2an1 a ≤ ⌊ n T 2 ⌋ a \leq \lfloor \frac{n}{T^2} \rfloor aT2n,且 ⌊ a b c ⌋ = ⌊ ⌊ a b ⌋ c ⌋ \lfloor \frac{a}{bc} \rfloor=\lfloor \frac{\lfloor \frac{a}{b} \rfloor}{c} \rfloor bca=cba,所以 原 式 = ∑ T = 1 ϕ ( T ) ∑ a = 1 ⌊ n T 2 ⌋ ⌊ n T 2 a ⌋ = ∑ T = 1 ϕ ( T ) ∑ a = 1 ⌊ n T 2 ⌋ ⌊ ⌊ n T 2 ⌋ a ⌋ 原式=\sum_{T=1}\phi(T)\sum_{a=1}^{\lfloor \frac{n}{T^2} \rfloor}\lfloor \frac{n}{T^2a} \rfloor=\sum_{T=1}\phi(T)\sum_{a=1}^{\lfloor \frac{n}{T^2} \rfloor}\lfloor \frac{\lfloor \frac{n}{T^2} \rfloor}{a} \rfloor =T=1ϕ(T)a=1T2nT2an=T=1ϕ(T)a=1T2naT2n
因为当 ⌊ n T 2 ⌋ ≥ 1 \lfloor \frac{n}{T^2} \rfloor \geq 1 T2n1 T ≤ ⌊ n ⌋ T \leq \lfloor \sqrt{n} \rfloor Tn ,所以
原 式 = ∑ T = 1 ⌊ n ⌋ ϕ ( T ) ∑ a = 1 ⌊ n T 2 ⌋ ⌊ ⌊ n T 2 ⌋ a ⌋ 原式=\sum_{T=1}^{\lfloor \sqrt{n} \rfloor}\phi(T)\sum_{a=1}^{\lfloor \frac{n}{T^2} \rfloor}\lfloor \frac{\lfloor \frac{n}{T^2} \rfloor}{a} \rfloor =T=1n ϕ(T)a=1T2naT2n
我们发现,现在的式子可以被拆分为 ϕ ( T ) \phi(T) ϕ(T) ∑ a = 1 ⌊ n T 2 ⌋ ⌊ ⌊ n T 2 ⌋ a ⌋ \sum_{a=1}^{\lfloor \frac{n}{T^2} \rfloor}\lfloor \frac{\lfloor \frac{n}{T^2} \rfloor}{a} \rfloor a=1T2naT2n两部分计算。

计算 ϕ ( T ) \phi(T) ϕ(T)

我们发现我们要算出 1 1 1 ⌊ n ⌋ \lfloor \sqrt{n} \rfloor n 的所有整数的 ϕ \phi ϕ函数的值。注意到对于正整数 n n n和素数 p p p,有 ϕ ( p ) = p − 1 \phi(p)=p-1 ϕ(p)=p1,且当 p ∤   n p \not| \space n p n ϕ ( n p ) = ϕ ( n ) ϕ ( p ) = ( p − 1 ) ϕ ( n ) \phi(np) = \phi(n) \phi(p) =(p-1) \phi(n) ϕ(np)=ϕ(n)ϕ(p)=(p1)ϕ(n)、当 p ∣ n p|n pn ϕ ( n p ) = p ϕ ( n ) \phi(np)=p \phi(n) ϕ(np)=pϕ(n),于是我们考虑在一个线性筛法的基础上求出所有 ϕ \phi ϕ函数的值。我们在添加新素数时更新素数的函数值,并在筛数时根据情况讨论被筛数的函数值,这样就可以得出 1 1 1 ⌊ n ⌋ \lfloor \sqrt{n} \rfloor n 的所有整数的 ϕ \phi ϕ函数的值了。

计算 ∑ a = 1 ⌊ n T 2 ⌋ ⌊ ⌊ n T 2 ⌋ a ⌋ \sum_{a=1}^{\lfloor \frac{n}{T^2} \rfloor}\lfloor \frac{\lfloor \frac{n}{T^2} \rfloor}{a} \rfloor a=1T2naT2n

可以发现,对于 ⌊ ⌊ n T 2 ⌋ a ⌋ \lfloor \frac{\lfloor \frac{n}{T^2} \rfloor}{a} \rfloor aT2n,当式子中 n , T n,T n,T一定、 a a a逐渐增大时,式子的值可以被划分成一段段值相等的区间,且当 a a a增大到一定大小时,这种区间的大小会变得很可观。于是我们考虑从这个方向优化计算。我们考虑计算出每个区间的左右端点 l , r l,r l,r,并用一个变量累加每个区间里的总和以求出 ∑ a = 1 ⌊ n T 2 ⌋ ⌊ ⌊ n T 2 ⌋ a ⌋ \sum_{a=1}^{\lfloor \frac{n}{T^2} \rfloor}\lfloor \frac{\lfloor \frac{n}{T^2} \rfloor}{a} \rfloor a=1T2naT2n。可以发现, r = ⌊ n ⌊ n l ⌋ ⌋ = ⌊ n 区 间 内 数 字 的 值 ⌋ r=\lfloor \frac{n}{\lfloor \frac{n}{l} \rfloor} \rfloor=\lfloor \frac{n}{区间内数字的值} \rfloor r=lnn=n,且 下 一 个 区 间 的 左 端 点 = 当 前 区 间 的 右 端 点 + 1 下一个区间的左端点=当前区间的右端点+1 =+1,这样我们就能快速计算出每个区间的左右端点了。
此外,我们发现对于 ⌊ n T 2 ⌋ \lfloor \frac{n}{T^2} \rfloor T2n(以及 ∑ a = 1 ⌊ n T 2 ⌋ ⌊ ⌊ n T 2 ⌋ a ⌋ \sum_{a=1}^{\lfloor \frac{n}{T^2} \rfloor}\lfloor \frac{\lfloor \frac{n}{T^2} \rfloor}{a} \rfloor a=1T2naT2n),当 n n n一定、 T T T逐渐增大时也有类似的性质,于是我们也可以用类似的方法优化。

代码

根据思路,可以写出如下代码:

#include<cstdio> //定义头文件
#include<cmath>
using ll=long long; //将ll类型定义为long long类型
bool book[316228]; //筛法用的标记数组
ll prime[27294] /*筛法得出的素数*/ ,phi[316228]={0,1} /*phi函数的值*/ ;
int main()
{
	freopen("gcd.in","r",stdin); //定义文件输入输出
	freopen("gcd.out","w",stdout);
	ll n;
	scanf("%lld",&n); //读入n
	const ll sn=sqrt(n); //预处理floor(sqrt(n))
	for(ll i=2;i<=sn;++i) //通过筛法计算phi函数的值
	{
		if(!book[i])
		{
			prime[++prime[0]]=i; //增加一个素数
			phi[i]=i-1;
		}
		for(ll j=1,max_p=sn/i;j<=prime[0]&&prime[j]<=max_p;++j) //筛数
		{
			book[i*prime[j]]=1;
			if(i%prime[j]==0)
			{
				phi[i*prime[j]]=phi[i]*prime[j];
				break;
			}
			phi[i*prime[j]]=phi[i]*phi[prime[j]];
		}
	}
	for(ll i=2;i<=sn;++i) //求phi函数的前缀和,为下面准备
	{
		phi[i]+=phi[i-1];
	}
	ll ans=0; //统计答案
	for(ll l=1 /*区间左端点*/ ,val=n/(l*l) /*区间内数的值*/ ,r /*区间右端点*/ ;l<=sn&&val>0;l=r+1,val=n/(l*l)) //利用floor(n/T^2)的性质计算ans
	{
		r=sqrt(n/val); //计算右端点
		if(r>sn)
		{
			r=sn;
		}
		ll t=0; //统计sum(floor(floor(n/T^2)/a))的值
		for(ll i=1 /*区间左端点*/ ,v=val/i /*区间内数的值*/ ,j /*区间右端点*/ ;i<=val&&v>0;i=j+1,v=val/i) //利用floor(floor(n/T^2)/a)的性质计算t
		{
			j=val/v; //计算右端点
			if(j>val)
			{
				j=val;
			}
			t+=(j-i+1)*v; //更新t
		}
		ans+=(phi[r]-phi[l-1])*t; //更新ans
	}
	printf("%lld",ans); //输出ans
	return 0;
}

总结

这是一道比较好的数论题,考察了多个数论技巧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值