题目链接:计蒜客 A1956 Sum
题目大意:
无平方整数是不能被任何除\(1\)以外的平方数整除的整数,例如,\(6 = 2 \times 3\)是无平方的,但是\(12 = 2^2 \times 3\)不是,因为\(2^2\)是一个平方数。有些整数可以分解为两个无平方整数的乘积,分解方式可能不止一种。例如,\(6 = 1 \times 6 = 6 \times 1 = 2 \times 3 = 3 \times 2\),如果\(a \neq b\),\(n = a \times b\)和\(n = b \times a\)被认为是不同的。
将\(n\)分解成形如\(n = a \times b\)这样的两个无平方整数的乘积,设\(f(n)\)为分解方式的数量,求\(\sum_{i = 1}^{n}f(i)\)。
题解:
由于任意一个数\(n\)可以表示为\(n=p^{a_1}_1 \times {p}^{a_2}_2 \times...\),\(p_1,p_2...\)为质数。
所以\(n=p_i^{a_i} \times x\),由题意知\(a_i\)只能为\(1\)或\(2\),否则无法拆分出符合条件的情况。
当\(a_i\)为\(1\)时,一个素数有两种拆分方式,所以贡献为\(2\);当\(a_i\)为\(2\)时,只有将一个\(p_i\)分配到\(x\)里去,且\(x\)本身不可整除\(p_i\)时,才能满足条件,因此贡献为\(1\)。
可得到递推式:\(\left\{
\begin{matrix}
&f(n)=2\times f(x),&a_i=1 \\
&f(n)=f(x),&a_i=2 \\
&f(n)=0,&a_i=3
\end{matrix}
\right.\)。
再用前缀和记录结果。每次查询为\(O(1)\)。
#include <cstdio>
#include <iostream>
using namespace std;
#define N 20000010
bool vis[N];
int f[N], prime[N], T, n;
long long sum[N];
void init() {
int cnt = 0;
f[1] = 1;
for (int i = 2; i <= N; ++i) {
if (!vis[i]) {
prime[++cnt] = i;
f[i] = 2;
}
for (int j = 1; j <= cnt && (prime[j] * i) < N; ++j) {
int num = i * prime[j];
vis[num] = true;
if (i % prime[j]) {
f[num] = 2 * f[i];
} else if (i % (prime[j] * prime[j]) == 0) {
f[num] = 0;
} else {
f[num] = f[i / prime[j]];
break;
}
}
}
for (int i = 1; i <= N; ++i) {
sum[i] = sum[i - 1] + f[i];
}
}
int main() {
init();
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
printf("%lld\n", sum[n]);
}
return 0;
}