×

第十篇: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;
}
posted @ 2026-10-05 17:27  shiori123  阅读(4)  评论(0)    收藏  举报