1. 程式人生 > 其它 >AtCoder Beginner Contest 254 - D - Together Square 題解解釋

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;
}