题解:【蓝桥杯 2018 国 B】 矩阵求和

题目链接

求:

\[\sum_{i=1}^{n} \sum_{j=1}^{n} \gcd(i,j)^2 \]

直接大力推式子:

\[\begin{align*} \sum_{d=1}^{n} d \sum_{i=1}^{n} \sum_{j=1}^{n} [\gcd(i,j)^2 == d] \\ \sum_{d=1}^{n} d^2 \sum_{i=1}^{n} \sum_{j=1}^{n} [\gcd(i,j) == d] \\ \sum_{d=1}^{n} d^2 \sum_{i=1}^{\lfloor \frac{n}{d} \rfloor} \sum_{j=1}^{\lfloor \frac{n}{d} \rfloor} [\gcd(i,j) == 1] \\ \end{align*} \]

莫反:

\[\sum_{d=1}^{n} d^2 \sum_{i=1}^{\lfloor \frac{n}{d} \rfloor} \mu(i) {\lfloor \frac{n}{d \times i} \rfloor}^2 \]

预处理 \(\mu\) 的前缀和,整除分块即可。

\(Code\)

//sum是前缀和
Mobius(MAX-10);
n=read();
for(int d=1;d<=n;++d)
{
	int res=0;
	int N=n/d;
	for(int l=1,r;l<=N;l=r+1)
	{
		r=N/(N/l);
		res+=(sum[r]-sum[l-1])*(N/l)*(N/l); res%=m;
	}
	ans+=res*d*d; ans%=m;
}
cout<<(ans+m)%m;

但是一看跑出了 \(4s\),尽管可以通过,但是效率是远远不够的,实际上这个题的思路远没有这么复杂。

考虑这个式子:

\[\sum_{d=1}^{n} d^2 \sum_{i=1}^{\lfloor \frac{n}{d} \rfloor} \sum_{j=1}^{\lfloor \frac{n}{d} \rfloor} [\gcd(i,j) == 1] \]

从定义上理解,后面的两个求和实则是在求 \(1 \sim \lfloor \frac{n}{d} \rfloor\) 这个范围内互质的数对的个数,也就是这个范围上欧拉函数的和。由于 \((i,j)\)\((j,i)\) 算两对,所以计算欧拉函数前缀和时还要乘二。类似的题目有[SDOI2008] 仪仗队

这样式子就被化成了:

\[\sum_{d=1}^{n} 2 \times d^2 \sum_{i=1}^{\lfloor \frac{n}{d} \rfloor} \phi(i) \]

预处理出前缀和即可 \(O(n)\) 计算。

\(Code\)

//sum是前缀和
n=read();
Phi(n);
for(int i=2;i<=n;++i)
	sum[i]=(sum[i-1]+phi[i]*2)%mod;
for(int i=1;i<=n;++i)
	ans=(ans+(sum[n/i]*i*i)%mod)%mod;
cout<<(ans+mod)%mod;
posted @ 2022-11-12 09:01  LgxTpre  阅读(92)  评论(0编辑  收藏  举报