51Nod1584 加权约数和-题解

又是一道非常神奇的数论题,学到了很多又花了一晚上QWQ

题目地址

题目大意

多组询问 T ≤ 50000 T\leq 50000 T50000,每次给定一个 n ≤ 1 0 6 n\leq 10^6 n106,询问下面式子在 m o d   1 0 9 + 7 {\rm mod}\ 10^9+7 mod 109+7意义下的值:

∑ i = 1 n ∑ j = 1 n max ⁡ ( i , j ) × σ 1 ( i j ) \sum_{i=1}^n\sum_{j=1}^n\max(i,j)\times \sigma_1(ij) i=1nj=1nmax(i,j)×σ1(ij)

其中 σ 1 ( i ) \sigma_1(i) σ1(i)表示 i i i的约数之和。


这次居然连 max ⁡ \max max都跑进去了,emmmm…

我们还是先把不好看的 max ⁡ \max max消除掉,所以对于每个 i i i,我们枚举比它小的 j j j,那么 max ⁡ ( i , j ) = i \max(i,j)=i max(i,j)=i,由于 ( i , j ) , ( j , i ) (i,j),(j,i) (i,j),(j,i)算两次,但是 ( i , i ) (i,i) (i,i)算一次,所以原式转化为:

2 × ( ∑ i = 1 n ∑ j = 1 i i × σ 1 ( i j ) ) − ∑ i = 1 n i σ 1 ( i 2 ) 2\times\left(\sum_{i=1}^n\sum_{j=1}^ii\times \sigma_1(ij)\right)-\sum_{i=1}^ni\sigma_1(i^2) 2×(i=1nj=1ii×σ1(ij))i=1niσ1(i2)

我们把它分成两部分分析:


一个是前半部分:

∑ i = 1 n ∑ j = 1 i i × σ 1 ( i j ) \sum_{i=1}^n\sum_{j=1}^ii\times \sigma_1(ij) i=1nj=1ii×σ1(ij)

根据这个题的经验,我们显然可以将后面的那一个 σ 1 ( i j ) \sigma_1(ij) σ1(ij)变换掉:

∑ i = 1 n ∑ j = 1 i i × σ 1 ( i j ) = ∑ i = 1 n ∑ j = 1 i i ∑ x ∣ i ∑ y ∣ j [ g c d ( x , y ) = 1 ] x j y \begin{aligned} \sum_{i=1}^n\sum_{j=1}^ii\times \sigma_1(ij)=& \sum_{i=1}^n\sum_{j=1}^ii\sum_{x|i}\sum_{y|j}[gcd(x,y)=1]\frac{xj}{y} \end{aligned} i=1nj=1ii×σ1(ij)=i=1nj=1iixiyj[gcd(x,y)=1]yxj

然后大都是这个题的套路,我们作如下变换:
∑ i = 1 n ∑ j = 1 i i × σ 1 ( i j ) = ∑ i = 1 n ∑ j = 1 i i ∑ x ∣ i ∑ y ∣ j [ g c d ( x , y ) = 1 ] x j y = ∑ i = 1 n i ∑ j = 1 i ∑ x ∣ i ∑ y ∣ j x j y ∑ w ∣ x , w ∣ y μ ( w ) = ∑ w = 1 n μ ( w ) ∑ w ∣ x x ∑ x ∣ i i ∑ w ∣ y ∑ y ∣ j j y = ∑ w = 1 n μ ( w ) ∑ x = 1 ⌊ n w ⌋ x w ∑ x ∣ i i w ∑ y = 1 ⌊ n w ⌋ ∑ y ∣ j j w y w = ∑ w = 1 n μ ( w ) w 2 ∑ x = 1 ⌊ n w ⌋ x ∑ x ∣ i i ∑ y = 1 ⌊ n w ⌋ ∑ y ∣ j j y = ∑ w = 1 n μ ( w ) w 2 ∑ i = 1 ⌊ n w ⌋ i ∑ x ∣ i x ∑ j = 1 ⌊ n w ⌋ ∑ y ∣ j j y \begin{aligned} \sum_{i=1}^n\sum_{j=1}^ii\times \sigma_1(ij)=& \sum_{i=1}^n\sum_{j=1}^ii\sum_{x|i}\sum_{y|j}[gcd(x,y)=1]\frac{xj}{y} \\ =& \sum_{i=1}^ni\sum_{j=1}^i\sum_{x|i}\sum_{y|j}\frac{xj}{y}\sum_{w|x,w|y}\mu(w) \\ =& \sum_{w=1}^n\mu(w)\sum_{w|x}x\sum_{x|i}i\sum_{w|y}\sum_{y|j}\frac{j}{y} \\ =& \sum_{w=1}^n\mu(w)\sum_{x=1}^{\lfloor\frac{n}{w}\rfloor}xw\sum_{x|i}iw\sum_{y=1}^{\lfloor\frac{n}{w}\rfloor}\sum_{y|j}\frac{jw}{yw} \\ =& \sum_{w=1}^n\mu(w)w^2\sum_{x=1}^{\lfloor\frac{n}{w}\rfloor}x\sum_{x|i}i\sum_{y=1}^{\lfloor\frac{n}{w}\rfloor}\sum_{y|j}\frac{j}{y} \\ =& \sum_{w=1}^n\mu(w)w^2\sum_{i=1}^{\lfloor\frac{n}{w}\rfloor}i\sum_{x|i}x\sum_{j=1}^{\lfloor\frac{n}{w}\rfloor}\sum_{y|j}\frac{j}{y} \end{aligned} i=1nj=1ii×σ1(ij)======i=1nj=1iixiyj[gcd(x,y)=1]yxji=1nij=1ixiyjyxjwx,wyμ(w)w=1nμ(w)wxxxiiwyyjyjw=1nμ(w)x=1wnxwxiiwy=1wnyjywjww=1nμ(w)w2x=1wnxxiiy=1wnyjyjw=1nμ(w)w2i=1wnixixj=1wnyjyj

因为 ∑ y ∣ j j y = ∑ y ∣ j y \sum_{y|j}\frac{j}{y}=\sum_{y|j}y yjyj=yjy,而根据在这个题目的技巧,我们知道 σ 1 ( j ) = ∑ y ∣ j y \sigma_1(j)=\sum_{y|j}y σ1(j)=yjy,所以上面继续可以变换为:

∑ w = 1 n μ ( w ) w 2 ∑ i = 1 ⌊ n w ⌋ i ∑ x ∣ i x ∑ j = 1 ⌊ n w ⌋ ∑ y ∣ j j y = ∑ w = 1 n μ ( w ) w 2 ∑ i = 1 ⌊ n w ⌋ i σ 1 ( i ) ∑ j = 1 ⌊ n w ⌋ σ 1 ( j ) \begin{aligned} \sum_{w=1}^n\mu(w)w^2\sum_{i=1}^{\lfloor\frac{n}{w}\rfloor}i\sum_{x|i}x\sum_{j=1}^{\lfloor\frac{n}{w}\rfloor}\sum_{y|j}\frac{j}{y}=& \sum_{w=1}^n\mu(w)w^2\sum_{i=1}^{\lfloor\frac{n}{w}\rfloor}i\sigma_1(i)\sum_{j=1}^{\lfloor\frac{n}{w}\rfloor}\sigma_1(j) \end{aligned} w=1nμ(w)w2i=1wnixixj=1wnyjyj=w=1nμ(w)w2i=1wniσ1(i)j=1wnσ1(j)

然后我们可以 O ( n ) O(n) O(n)的筛出 σ 1 , μ \sigma_1,\mu σ1,μ,并预处理上面的所用到的前缀和。


一个是后半部分:

∑ i = 1 n i σ 1 ( i 2 ) \sum_{i=1}^ni\sigma_1(i^2) i=1niσ1(i2)

这个处理就和上面的十分类似了:

∑ i = 1 n i σ 1 ( i 2 ) = ∑ i = 1 n i ∑ x ∣ i ∑ y ∣ i [ g c d ( x , y ) = 1 ] i x y = ∑ i = 1 n i ∑ x ∣ i ∑ y ∣ i i x y ∑ w ∣ x , w ∣ y μ ( w ) = ∑ w = 1 n μ ( w ) ∑ w ∣ i i ∑ w ∣ x , x ∣ i x ∑ w ∣ y , y ∣ i i y = ∑ w = 1 n μ ( w ) ∑ i = 1 ⌊ n w ⌋ i w ∑ x ∣ i x w ∑ y ∣ i i w y w = ∑ w = 1 n μ ( w ) w 2 ∑ i = 1 ⌊ n w ⌋ i ∑ x ∣ i x ∑ y ∣ i i y = ∑ w = 1 n μ ( w ) w 2 ∑ i = 1 ⌊ n w ⌋ i σ 1 ( i ) σ 1 ( i ) = ∑ w = 1 n μ ( w ) w 2 ∑ i = 1 ⌊ n w ⌋ i σ 1 2 ( i ) \begin{aligned} \sum_{i=1}^ni\sigma_1(i^2)=& \sum_{i=1}^ni\sum_{x|i}\sum_{y|i}[gcd(x,y)=1]\frac{ix}{y} \\ =& \sum_{i=1}^ni\sum_{x|i}\sum_{y|i}\frac{ix}{y}\sum_{w|x,w|y}\mu(w) \\ =& \sum_{w=1}^n\mu(w)\sum_{w|i}i\sum_{w|x,x|i}x\sum_{w|y,y|i}\frac{i}{y} \\ =& \sum_{w=1}^n\mu(w)\sum_{i=1}^{\lfloor\frac{n}{w}\rfloor}iw\sum_{x|i}xw\sum_{y|i}\frac{iw}{yw} \\ =& \sum_{w=1}^n\mu(w)w^2\sum_{i=1}^{\lfloor\frac{n}{w}\rfloor}i\sum_{x|i}x\sum_{y|i}\frac{i}{y} \\ =& \sum_{w=1}^n\mu(w)w^2\sum_{i=1}^{\lfloor\frac{n}{w}\rfloor}i\sigma_1(i)\sigma_1(i) \\ =& \sum_{w=1}^n\mu(w)w^2\sum_{i=1}^{\lfloor\frac{n}{w}\rfloor}i\sigma_1^2(i) \end{aligned} i=1niσ1(i2)=======i=1nixiyi[gcd(x,y)=1]yixi=1nixiyiyixwx,wyμ(w)w=1nμ(w)wiiwx,xixwy,yiyiw=1nμ(w)i=1wniwxixwyiywiww=1nμ(w)w2i=1wnixixyiyiw=1nμ(w)w2i=1wniσ1(i)σ1(i)w=1nμ(w)w2i=1wniσ12(i)


此时,我们可以同样的预处理,然后带入原式,每次数论分块,然后 O ( n ) O(\sqrt n) O(n )的回答,复杂度大概 O ( n + T n ) O(n+T\sqrt n) O(n+Tn ),但是最大数据有 1 0 6 + 2 × 50000 × 1000 10^6+2\times 50000\times 1000 106+2×50000×1000,差不多一亿左右,而且加上大常数,最大数据大概跑3s左右,虽然丧心病狂地卡卡常就能过,但是肯定还有更优秀的做法。


我们将上面的两个式子带回原式,作如下变换:

a n s ( n ) = 2 × ( ∑ w = 1 n μ ( w ) w 2 ∑ i = 1 ⌊ n w ⌋ i σ 1 ( i ) ∑ j = 1 ⌊ n w ⌋ σ 1 ( j ) ) − ( ∑ w = 1 n μ ( w ) w 2 ∑ i = 1 ⌊ n w ⌋ i σ 1 2 ( i ) ) = ∑ w = 1 n μ ( w ) w 2 ( ∑ i = 1 ⌊ n w ⌋ ( 2 ⋅ i σ 1 ( i ) − i σ 1 2 ( i ) ) ∑ j = 1 ⌊ n w ⌋ σ 1 ( j ) ) = ∑ w = 1 n μ ( w ) w 2 ( ∑ i = 1 ⌊ n w ⌋ i σ 1 ( i ) ( 2 ⋅ ∑ j = 1 ⌊ n w ⌋ σ 1 ( j ) − σ 1 ( i ) ) ) \begin{aligned} ans(n) =& 2\times\left(\sum_{w=1}^n\mu(w)w^2\sum_{i=1}^{\lfloor\frac{n}{w}\rfloor}i\sigma_1(i)\sum_{j=1}^{\lfloor\frac{n}{w}\rfloor}\sigma_1(j)\right)-\left(\sum_{w=1}^n\mu(w)w^2\sum_{i=1}^{\lfloor\frac{n}{w}\rfloor}i\sigma_1^2(i)\right) \\ =& \sum_{w=1}^n\mu(w)w^2\left(\sum_{i=1}^{\lfloor\frac{n}{w}\rfloor}(2\cdot i\sigma_1(i)-i\sigma_1^2(i))\sum_{j=1}^{\lfloor\frac{n}{w}\rfloor}\sigma_1(j)\right) \\ =& \sum_{w=1}^n\mu(w)w^2\left(\sum_{i=1}^{\lfloor\frac{n}{w}\rfloor}i\sigma_1(i)\left(2\cdot \sum_{j=1}^{\lfloor\frac{n}{w}\rfloor}\sigma_1(j)-\sigma_1(i)\right)\right) \end{aligned} ans(n)===2×w=1nμ(w)w2i=1wniσ1(i)j=1wnσ1(j)w=1nμ(w)w2i=1wniσ12(i)w=1nμ(w)w2i=1wn(2iσ1(i)iσ12(i))j=1wnσ1(j)w=1nμ(w)w2i=1wniσ1(i)2j=1wnσ1(j)σ1(i)

如果我们能预处理处所有的 a n s ( n ) ans(n) ans(n),然后每次 O ( 1 ) O(1) O(1)的回答,那就会优秀的多,所以我们发现 a n s ( n ) ans(n) ans(n)不好直接求,所以考虑一个神奇的东西:差分

其实这个技巧在前面做过的题目中出现过:Imagine大佬-Orz,Imagine这个题目就用的差分做的。

我们来看,差分后如何计算:

c a n s ( n ) = a n s ( n ) − a n s ( n − 1 ) \begin{aligned} cans(n)=&ans(n)-ans(n-1) \end{aligned} cans(n)=ans(n)ans(n1)

直接算,发现并不好算QAQ,所以我们考虑对于一个单个的 n n n,那么定义它的贡献就为:

= ∑ d ∣ n μ ( d ) d 2 ( ( 2 ⋅ ∑ i = 1 ⌊ n d ⌋ σ 1 ( i ) − σ 1 ( ⌊ n d ⌋ ) ) ⋅ ⌊ n d ⌋ ⋅ σ 1 ( ⌊ n d ⌋ ) ) =\sum_{d|n}\mu(d)d^2\left(\left(2\cdot \sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sigma_1(i)-\sigma_1(\lfloor\frac{n}{d}\rfloor)\right)\cdot \lfloor\frac{n}{d}\rfloor\cdot \sigma_1(\lfloor\frac{n}{d}\rfloor)\right) =dnμ(d)d22i=1dnσ1(i)σ1(dn)dnσ1(dn)

其实这里的意思,对于每一个 c a n s ( n ) cans(n) cans(n),对其进行贡献的有它的因子 d d d,然后带入上面的式子可以得到这个。

a n s ( n ) ans(n) ans(n),就是 c a n s ( 1 ∼ n ) cans(1\sim n) cans(1n)所有的贡献,所以我们此时再求出 c a n s cans cans的前缀和就是 a n s ans ans了。

也就是我们将一个前缀和中的一些项拆了出来,而两个前缀和之间差的就是 n n n的贡献,所以差分的 c a n s cans cans就等于这个。

而上面的那个 c a n s cans cans的预处理,我们用类似埃氏筛,枚举因子倍数 O ( n l o g n ) O(nlogn) O(nlogn)的预处理即可。

所以总的复杂度变成了 O ( n l o g n + T ) O(nlogn+T) O(nlogn+T),就不卡常啦!代码还是比较好写。

51Nod官网上还有一种不同的题解,方法差不多但是又有很多不同的技巧,有兴趣的可以去官网看。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int M=1e6+10,N=1e5+10,MAX=1e6+1;
const ll Mod=1e9+7;
ll prime[N],sigma[M],mu[M],c[M],cnt,ans[M];
bool vis[M];
void init(){
	mu[1]=sigma[1]=1;
	for(ll i=2;i<MAX;i++){
		if(!vis[i]){
			prime[++cnt]=i;
			mu[i]=-1;
			sigma[i]=1+i;
			c[i]=1+i;
		}
		for(ll j=1,v;j<=cnt&&i*prime[j]<MAX;j++){
			v=i*prime[j];
			vis[v]=1;
			if(!(i%prime[j])){
				c[v]=c[i]*prime[j]+1;
				sigma[v]=sigma[i]/c[i]*c[v];
				break;
			}
			mu[v]=-mu[i];
			sigma[v]=sigma[i]*sigma[prime[j]];
			c[v]=prime[j]+1;
		}
	}
	ll sum=1;
	for(ll i=2;i<MAX;i++){
		sum=(sum+sigma[i])%Mod;
		sigma[i]=(i*sigma[i]%Mod*((2ll*sum-sigma[i])%Mod)%Mod)%Mod;
		if(sigma[i]<0)sigma[i]+=Mod;
	}
	for(ll i=1,v;i<MAX;i++){
		v=((i*i)%Mod*mu[i])%Mod;
		if(v<0)v+=Mod;
		for(ll j=1;i*j<MAX;j++){
			ans[i*j]=(ans[i*j]+v*sigma[j]%Mod)%Mod;
		}
	}
	for(ll i=2;i<MAX;i++)ans[i]=(ans[i-1]+ans[i])%Mod;
}
int T,n;
int main(){
	init();
	scanf("%d",&T);
	for(int cas=1;cas<=T;cas++){
		scanf("%d",&n);
		printf("Case #%d: %lld\n",cas,ans[n]);
	}
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

VictoryCzt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值