质因数分解 枚举

因为答案肯定在 这个区间里面,因此我们可以考虑枚举所有可能的答案并逐一校验。检验时,我们可以枚举 让其他 都改变成 。时间复杂度为 ,但是由于 达到了 ,因此会超时。

考虑优化校验复杂度。能够发现,当 的时候,只需要除可能解的余数一样就行了。因此,我们可以新建一个表用来存余数对应的数量,找到一个数量大于等于 的余数。时间复杂度为 ,仍然超时。

这次,我们不再寻找解了,而是枚举 找到最优解。对于所有 ,都可以通过一个数 满足 减到 ,也就是说可能的 必须是 的因数。因此,我们先求出所有的因数,存进 map 里面,再找到一个最大的因数 满足 的数量大于等于 就行了。时间复杂度

#include <iostream>
#include <unordered_set>
#include <unordered_map>
#include <algorithm>
#include <vector>
 
using namespace std;
 
const int kMaxN = 45;
 
int a[kMaxN], t, n, ans;
vector<int> v;
unordered_map<int, int> f;
 
unordered_set<int> calc(int x) {
  unordered_set<int> s;
  for (int i = 1; i * i <= x; i++) {
    if (x % i == 0) {
      s.insert(i);
      s.insert(x / i);
    }
  }
  return s;
}
 
int main() {
  ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
  for (cin >> t; t; t--) {
    cin >> n;
    ans = -1e9;
    for (int i = 1; i <= n; ++i) {
      cin >> a[i];
    }
    sort(a + 1, a + n + 1);
    // 枚举要变成的
    for (int i = 1; i <= n; i++) {
      // 清空
      int times = 0;
      f.clear();
      v.clear();
      // 枚举其他的数
      for (int j = 1; j <= n; j++) {
        if (a[j] == a[i]) {          // 如果大小一样
          times++;                   // 记录数量
        } else if (a[j] > a[i]) {    // 大于 a[i]
          v.push_back(a[j] - a[i]);  // 加入 vector
        }
      }
      // 如果一样的已经超过了 n/2 就有无数种解
      if (times >= n / 2) {
        ans = 1e9;
        continue;
      }
      // 求因数并记录
      for (int i : v) {
        for (int j : calc(i)) {
          f[j]++;
        }
      }
      // 找最大的答案
      for (auto j : f) {
        if (j.second >= n / 2 - times) {
          ans = max(ans, j.first);
        }
      }
    }
    cout << (ans == 1e9 ? -1 : ans) << '\n';
  }
  return 0;
}