计蒜客 A1956 Sum

题目链接:计蒜客 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{array}{l} f(n)=2\times f(x),a_i=1 \\ f(n)=f(x),a_i=2 \\ f(n)=0,a_i=3 \end{array} \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;
}
posted @ 2022-02-02 19:21  ZZHHOOUU  阅读(20)  评论(0编辑  收藏  举报