51Nod1584 加權約數和-題解

VictoryCzt發表於2018-12-24

又是一道非常神奇的數論題,學到了很多又花了一晚上QWQ

題目地址

題目大意

多組詢問T50000T\leq 50000,每次給定一個n106n\leq 10^6,詢問下面式子在mod 109+7{\rm mod}\ 10^9+7意義下的值:

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

其中σ1(i)\sigma_1(i)表示ii的約數之和。


這次居然連max\max都跑進去了,emmmm…

我們還是先把不好看的max\max消除掉,所以對於每個ii,我們列舉比它小的jj,那麼max(i,j)=i\max(i,j)=i,由於(i,j),(j,i)(i,j),(j,i)算兩次,但是(i,i)(i,i)算一次,所以原式轉化為:

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

我們把它分成兩部分分析:


一個是前半部分:

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

根據這個題的經驗,我們顯然可以將後面的那一個σ1(ij)\sigma_1(ij)變換掉:

i=1nj=1ii×σ1(ij)=i=1nj=1iixiyj[gcd(x,y)=1]xjy \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]xjy=i=1nij=1ixiyjxjywx,wyμ(w)=w=1nμ(w)wxxxiiwyyjjy=w=1nμ(w)x=1nwxwxiiwy=1nwyjjwyw=w=1nμ(w)w2x=1nwxxiiy=1nwyjjy=w=1nμ(w)w2i=1nwixixj=1nwyjjy \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}

因為yjjy=yjy\sum_{y|j}\frac{j}{y}=\sum_{y|j}y,而根據在這個題目的技巧,我們知道σ1(j)=yjy\sigma_1(j)=\sum_{y|j}y,所以上面繼續可以變換為:

w=1nμ(w)w2i=1nwixixj=1nwyjjy=w=1nμ(w)w2i=1nwiσ1(i)j=1nwσ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}

然後我們可以O(n)O(n)的篩出σ1,μ\sigma_1,\mu,並預處理上面的所用到的字首和。


一個是後半部分:

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

這個處理就和上面的十分類似了:

i=1niσ1(i2)=i=1nixiyi[gcd(x,y)=1]ixy=i=1nixiyiixywx,wyμ(w)=w=1nμ(w)wiiwx,xixwy,yiiy=w=1nμ(w)i=1nwiwxixwyiiwyw=w=1nμ(w)w2i=1nwixixyiiy=w=1nμ(w)w2i=1nwiσ1(i)σ1(i)=w=1nμ(w)w2i=1nwiσ12(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}


此時,我們可以同樣的預處理,然後帶入原式,每次數論分塊,然後O(n)O(\sqrt n)的回答,複雜度大概O(n+Tn)O(n+T\sqrt n),但是最大資料有106+2×50000×100010^6+2\times 50000\times 1000,差不多一億左右,而且加上大常數,最大資料大概跑3s左右,雖然喪心病狂地卡卡常就能過,但是肯定還有更優秀的做法。


我們將上面的兩個式子帶回原式,作如下變換:

ans(n)=2×(w=1nμ(w)w2i=1nwiσ1(i)j=1nwσ1(j))(w=1nμ(w)w2i=1nwiσ12(i))=w=1nμ(w)w2(i=1nw(2iσ1(i)iσ12(i))j=1nwσ1(j))=w=1nμ(w)w2(i=1nwiσ1(i)(2j=1nwσ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)ans(n),然後每次O(1)O(1)的回答,那就會優秀的多,所以我們發現ans(n)ans(n)不好直接求,所以考慮一個神奇的東西:差分

其實這個技巧在前面做過的題目中出現過:Imagine大佬-Orz,Imagine這個題目就用的差分做的。

我們來看,差分後如何計算:

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

直接算,發現並不好算QAQ,所以我們考慮對於一個單個的nn,那麼定義它的貢獻就為:

=dnμ(d)d2((2i=1ndσ1(i)σ1(nd))ndσ1(nd)) =\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)

其實這裡的意思,對於每一個cans(n)cans(n),對其進行貢獻的有它的因子dd,然後帶入上面的式子可以得到這個。

ans(n)ans(n),就是cans(1n)cans(1\sim n)所有的貢獻,所以我們此時再求出canscans的字首和就是ansans了。

也就是我們將一個字首和中的一些項拆了出來,而兩個字首和之間差的就是nn的貢獻,所以差分的canscans就等於這個。

而上面的那個canscans的預處理,我們用類似埃氏篩,列舉因子倍數O(nlogn)O(nlogn)的預處理即可。

所以總的複雜度變成了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;
}

相關文章