AtCoder Beginner Contest 254 - D - Together Square 题解解释

原题

原文

Let \(f(N)\) be the largest square divisor of an integer \(N\).

Then, for integers \(i\) and \(j\), \(i \times j\) is a square number if and only if \(\frac{i \times j}{f(i) \times f(j)}\) is a square number.

Since \(\frac{i}{f(i)}\) is indivisible by a prime \(p\) twice or more, \(\frac{i \times j}{f(i) \times f(j)}\) is a square number if and only if \(\frac{i}{f(i)}=\frac{j}{f(j)}\)

Therefore, it is sufficient to find \(f(i)\) for each integer \(i(1\le i \le N)\), and to find \(\frac{i}{f(i)}\).

After checking if each integer from \(1\) through \(N\) is a square number, we can find \(f(i)\) by bruteforcing every divisor of \(i\).

The complexity is \(\mathrm{O}(N\log N)\).

翻译

我们令\(f(N)\)表示整数\(N\)的因数中, 最大的平方数.

那么, 对于整数 i,j ,当且仅当\(\frac{i \times j}{f(i) \times f(j)}\)是一个平方数时, \(i \times j\) 是一个平方数.

又因为 \(\frac{i}{f(i)}\)不能除以某个质数\(p\)两次或者两次以上, 故当且仅当\(\frac{i}{f(i)}=\frac{j}{f(j)}\)时, \(\frac{i \times j}{f(i) \times f(j)}\)是一个平方数.

因此, 只需对每个整数\(i(1\le i \le N)\), 寻找对应的\(f(i), \frac{i}{f(i)}\)即可.

在初始化完前\(N\)个数的平方数之后, 我们就可以通过枚举 \(i\) 的每个除数来寻找\(f(i)\).

算法复杂度是\(\mathrm{O}(N\log N)\).

上面的具体操作解释详见代码

解释

\(f(x)\)的含义

对于任意一个数\(x\), 都可进行质因数分解: \(x = \prod p_i^{e_i}\), 其中\(p_i\)为质数. 当 \(x\) 为平方数时, \(p_i^{e_i}\) 中的\(e_i\)将全为偶数. \(f(x)\) 可表示为\(\prod q_i^{e_i}\), 其中\(e_i\)均为偶数, \(q_i\)\(p_i\)的一个子集.

\(\frac{i}{f(i)}\)可表示为\(\prod w_i\), 其中\(w_i\)的次数均为\(1\).

e.g.

\[18 = 2 *3^2 \\ f(18)= 3^2 \\ \frac{18}{f(18)} = 2 \]

对于整数 i,j ,当且仅当\(\frac{i \times j}{f(i) \times f(j)}\)是一个平方数时, \(i \times j\) 是一个平方数

证明:

充分性:

\(\frac{i \times j}{f(i) \times f(j)}\)是一个平方数, 则可\(\frac{i \times j}{f(i) \times f(j)}\)表示为\(\prod p_i^{e_i}\), 其中\(e_i\)均为偶数.\(f(i), f(j)\) 可表示为\(\prod q_i^{e_i}, \prod k_i^{e_i}\), 其中\(e_i\)均为偶数.

显然, 它乘上\(f(i), f(j)\)之后, 各个因数都将是偶数次方, 故\(i \times j\)为一个平方数

必要性:

\(i \times j\)是一个平方数, 则\(i \times j\)可表示为\(\prod p_i^{e_i}\), 其中\(e_i\)均为偶数.\(f(i), f(j)\) 可表示为\(\prod q_i^{e_i}, \prod k_i^{e_i}\), 其中\(e_i\)均为偶数.

\(\frac{i \times j}{f(i) \times f(j)}\)不是一个平方数, 则其必有一个因数的次方为奇数次方, 记其为\(\alpha^t\), 其中\(t\)为奇数. 使\(\frac{i \times j}{f(i) \times f(j)}\)乘上\(f(i), f(j)\), 由于\(f(i), f(j)\)的各因数均为偶数次方, 因数\(\alpha\)的次方的奇偶性不会发生改变, 故此时\(i \times j\)的质因数分解中, 存在奇数次方的因数, 与其是平方数矛盾, 故原命题成立.

又因为 \(\frac{i}{f(i)}\)不能除以某个质数\(p\)两次或者两次以上, 故当且仅当\(\frac{i}{f(i)}=\frac{j}{f(j)}\)时, \(\frac{i \times j}{f(i) \times f(j)}\)是一个平方数

证明:

充分性:

\(\frac{i}{f(i)}=\frac{j}{f(j)}\)时, \(\frac{i \times j}{f(i) \times f(j)}\)显然是一个平方数, 其平方根即为\(\frac{i}{f(i)}=\frac{j}{f(j)}\)

必要性:

上文提到, \(\frac{i}{f(i)}\)可表示为\(\prod w_i\), 其中\(w_i\)的次数均为\(1\), 而一个平方数的质因数分解中的每个因数的次方都为偶数, 故\(\frac{j}{f(j)}\)的质因数分解中, 至少需要出现\(\prod w_i^{e_i}\), 其中\(e_i\)为奇数且只能为\(1\).

此时\(\frac{j}{f(j)}\)再增加任何一个因数的次数次方, 都不能使 \(\frac{i \times j}{f(i) \times f(j)}\)平方数, 故\(\frac{i}{f(i)}=\frac{j}{f(j)}\).

由于“当且仅当\(\frac{i \times j}{f(i) \times f(j)}\)是一个平方数时, \(i \times j\) 是一个平方数.”,并且“当且仅当\(\frac{i}{f(i)}=\frac{j}{f(j)}\)时, \(\frac{i \times j}{f(i) \times f(j)}\)是一个平方数”,故由乘法原理知,我们只需求“满足\(\frac{i}{f(i)}\times \frac{i}{f(i)}\)是平方数的 i 的选法”,答案就是满足条件的 \(i\) 的数量的平方.

代码

#include <bits/stdc++.h>
using namespace std;
int main(){
  int n;
  cin>>n;
  vector<bool> sq(n+1,false); // 记录 i 是否为平方数
  for(int i=1;i*i<=n;i++) sq[i*i]=true;
  vector<vector<int>> d(n+1); // d[i]记录的是 i 的所有因数,当然包括1和它本身
  for(int i=1;i<=n;i++){
    for(int j=i;j<=n;j+=i) d[j].push_back(i);
  }
  vector<int> cnt(n+1);
  for(int i=1;i<=n;i++){
    int f=0;
    for(int j=0;j<d[i].size();j++) if(sq[d[i][j]]) f=d[i][j];
    // 从小到大枚举因数,最后一个满足条件的就是最大的平方数因数
    cnt[i/f]++;
    // // 乘法原理,不同的 i ,可能对应同一个i/f(i),它们之间可以任意搭配
  }
  int ans=0;
  for(int i=1;i<=n;i++) ans+=cnt[i]*cnt[i];// 即上面所说的乘法原理
  cout<<ans<<endl;
}

posted @ 2022-06-05 19:32  tsrigo  阅读(214)  评论(4编辑  收藏  举报