题解:【蓝桥杯 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;