第十篇:P1891
题解补完计划:第十篇
(好啊好啊,都第十篇了,也算是第一个整十数了)。
显然,推式子:
\(\begin{aligned}
\sum_{i=1}^n [i, n] &= \sum_{i=1}^n \frac{i\times n}{(i, n)} = n\times \sum_{i=1}^n \frac{i}{(i,n)} = n\times\sum_{d|n} \frac{1}{d}\sum_{i=1}^n i [(i,n) = d] \\
&= n\times\sum_{d|n}\sum_{i=1}^{ d} i [(i,d) = 1]
\end{aligned}\)
我们观察式子 $$ \sum_{i=1}^{d} i [(i, d) = 1] $$
其本质就是在求所有与 \(d\) 互质的数的和,我们知道如果 \(k\) 与 \(n\) 互质,则 \(n-k\) 也与 \(n\) 互质,这是一对,和为 \(n\), 而一共有 \(\frac{\varphi_{d}}{2}\) 对,总和为 \(\frac{d \times\varphi_{d}}{2}\) 要注意 $ d = 1$ 的情况,因为 \(\varphi_1\times 1/2 = 0\) 但实际上等于 \(1\)。
所以原式转化为 \(n\times\sum_{d|n} \frac{d\times\varphi_d}{2}\),\(O(n\log n)\) 预处理即可,总时间复杂度 \(O(n \log n + T)\)。
代码:
#include<bits/stdc++.h>
using namespace std;
#define N 1000005
#define intl long long
#define For(i,a,b) for(intl i=a;i<=b;i++)
#define deo(i,a,b) for(intl i=a;i>=b;i--)
intl read() {
intl x=0,k=1;char ch=getchar();
while(!isdigit(ch)) {if(ch == '-') k=-1;ch=getchar();}
while(isdigit(ch)) {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*k;
}
intl n,phi[N];
vector<intl> prim;
bool vis[N];
void init() {
For(i,2,N-5) {
if(!vis[i]) prim.push_back(i), phi[i] = i-1;
for(auto x:prim) {
if(i*x > N-5) break;
vis[i*x] = 1;
if(i%x == 0) {
phi[i*x] = phi[i]*x;
break;
}
phi[i*x] = phi[i]*phi[x];
}
}
}
intl dp[N];
int main() {
init();
intl T = read();
For(i,1,N-5) dp[i] ++;
For(i,1,N-5) for(intl j = i; j <= N-5;j += i) dp[j] += phi[i]*i/2;
while(T--) {
n = read();
printf("%lld\n",dp[n]*n);
}
return 0;
}

浙公网安备 33010602011771号