[ABC254D] Together Square 题解

[ABC254D] Together Square Solution

更好的阅读体验戳此进入

题面

给定 $ n $,求满足以下条件的二元组 $ (i, j) $ 数量:$ 1 \le i, j \le n, i \times j = k^2(k \in \mathbb{N}^*) $。

Solution

首先有一个较为显然的想法,即埃筛 $ [1, n] $ 每个数的所有因数,然后枚举每个 $ i^2, i \in [1, n] $,将 $ i \times i $ 转化为 $ (i \times t) \times (\dfrac{i}{t}) $,其中 $ t $ 为 $ i $ 的因数,然后如果 $ i \times t \le n $ 那么若 $ t = 1 $ 则 $ ans \leftarrow ans + 1 $,反之 $ ans \leftarrow ans + 2 $。不过很遗憾这个很简单也很好写的思路是假的,不难发现比如 $ 6 \times 6 \Rightarrow 4 \times 9 $,这里的因数是 $ \dfrac{3}{2} $,然后我们忽略了,所以会漏。

考虑正解,有个妙妙转化,即将原式的 $ i, j $ 转化为 $ i = a^2 \times c, j = b^2 \times c $,然后我们钦定 $ i \lt j $,此时计算后对于每个答案都 $ \times 2 $ 可以不漏 $ i \gt j $ 的部分,然后将最后的答案加上 $ n $ 即不漏 $ i = j $ 的部分。

然后考虑处理钦定 $ i \lt j $ 后的答案,不难想到有 $ i \lt j \lt n \Rightarrow a^2 \times c \lt b^2 \times c \lt n \Rightarrow a^2 \lt b^2 \lt \dfrac{n}{c} \Rightarrow a \lt b \lt \sqrt{\dfrac{n}{c}} $。

于是不难发现 $ a, b $ 都是 $ \sqrt{n} $ 级别的,于是枚举 $ a, b $,对于确定的 $ a, b $,则显然有 $ c \in [1, \dfrac{n}{b^2}] $,则此时的答案贡献即为 $ 2 \times \lfloor \dfrac{n}{b^2} \rfloor $。然后发现这个东西还是假的,会重,即对于 $ \gcd(a, b) \neq 1 $ 的 $ c $,显然会被 $ a' = \dfrac{a}{\gcd(a, b)}, b' = \dfrac{b}{\gcd(a, b)} $ 所包含,所以不难想到只要将对答案的贡献转化为 $ 2 \times \lfloor \dfrac{n}{b^2} \rfloor \times [\gcd(a, b) = 1] $ 即可不重不漏地求出答案。

Code

#define _USE_MATH_DEFINES
#include <bits/stdc++.h>

#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}

using namespace std;

mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}

typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;

template < typename T = int >
inline T read(void);

int N;
ll ans(0);

int main(){
    N = read();
    for(int a = 1; a * a <= N; ++a)
        for(int b = a + 1; b * b <= N; ++b)
            if(__gcd(a, b) == 1)
                ans += 2 * (N / (b * b));
    printf("%lld\n", ans + N);
    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}

template < typename T >
inline T read(void){
    T ret(0);
    int flag(1);
    char c = getchar();
    while(c != '-' && !isdigit(c))c = getchar();
    if(c == '-')flag = -1, c = getchar();
    while(isdigit(c)){
        ret *= 10;
        ret += int(c - '0');
        c = getchar();
    }
    ret *= flag;
    return ret;
}

UPD

update-2022_12_06 初稿

posted @ 2023-01-07 15:33  Tsawke  阅读(49)  评论(0)    收藏  举报