P3540 SQU-Squarks Sol

下面将可能的答案称为 \(a_1,...,a_n\)

因为题目只给你 \(a_i+a_j\),所以想到特殊的最小值、最大值。

不妨令 \(a\) 从小到大排序,这样不改变两两的和,且容易想到正解。

考虑最小值,\(a_1+a_2\),那么次小值也可以知道是 \(a_1+a_3\)

那么 \(a_2+a_3\) 呢?但是我们不知道第三小的值是 \(a_1+a_4\) 还是 \(a_2+a_3\)

所以想到枚举 \(a_2+a_3\),那么就可以得到 \(a_1,a_2,a_3\) 了。

接着我们就可以枚举剩下的最小值,一定是 \(a_1+a_4\)

由于知道了 \(a_1,a_2,a_3\),就可以得到 \(a_4\) 的值。

接着把 \(a_1+a_4,a_2+a_4,a_3+a_4\) 从输入的数组中剔除,以此类推,可以得出答案。

那么枚举 \(a_2+a_3\) 时,发现只有 \(a_1+a_i\) 才可能 \(<a_2+a_3\)

因为 \(a_1<a_2\),所以 \(a_1+a_i<a_2+a_i(3\le i \le n)\)

从而有枚举最小的 \(n-2\) 个数(除去 \(a_1+a_2\)\(a_1+a_3\)),依次钦定为 \(a_2+a_3\) 即可。

最后由于 \(a_i+a_j\) 可能有重复,所以枚举的 \(a_2+a_3\) 也会有重复,于是对答案进行去重才能过。

下面是代码,有一些细节。

#include <bits/stdc++.h>
using namespace std;

const int N = 5e4 + 10, M = 310;
int m, n, cnt, a[N], res[M][M];
multiset <int> S; int ret[M];
map <unsigned, bool> mp;
// 用来对答案进行去重

int main() {
  ios_base::sync_with_stdio(false); cin.tie(0), cout.tie(0);
  cin >> m; n = m * (m - 1) >> 1;
  for (int i = 1; i <= n; ++i) cin >> a[i];
  sort(a + 1, a + 1 + n);
  int a12 = a[1], a13 = a[2];
  // a12 = a1 + a2, a13 = a1 + a3
  // 下面用 S 来表示剩余可以取到的和的集合
  for (int i = 3; i <= m; ++i) {
    // 枚举 a2 + a3
    S.clear(); for (int j = 3; j <= n; ++j) S.insert(a[j]);
    int a23 = a[i], all = a12 + a13 + a23; if (all & 1) continue;
    all >>= 1; auto it = S.find(a23); S.erase(it); int tot = 4;
    ret[1] = all - a23, ret[2] = all - a13, ret[3] = all - a12;
    if (ret[1] <= 0) continue;
    bool tag = true;
    for (int j = 4; j <= m; ++j) {
      int cur = *S.begin(); ret[j] = cur - ret[1]; S.erase(S.begin());
      for (int k = 2; k < j; ++k) {
        it = S.find(ret[k] + ret[j]); // 全部删掉,避免单调性被破坏
        if (it == S.end()) { tag = false; break; } S.erase(it);
      }
    }
    if (!tag) continue;
    bool f = true;
    for (int j = 2; j <= m; ++j) f &= (ret[j] > ret[j - 1]);
    if (f) {
      ++cnt;
      for (int j = 1; j <= m; ++j) res[cnt][j] = ret[j];
    }
  }
  int realcnt = 0;
  for (int i = 1; i <= cnt; ++i) {
    unsigned hash = 0;
    for (int j = 1; j <= m; ++j) hash = hash * 131 + res[i][j];
    if (mp[hash]) { res[i][1] = 0; continue; } mp[hash] = true; ++realcnt;
  }
  cout << realcnt << endl;
  for (int i = 1; i <= realcnt; ++i) {
    if (!res[i][1]) continue;
    for (int j = 1; j <= m; ++j) cout << res[i][j] << ' '; cout << endl;
  }
  return 0;
}
posted @ 2022-09-05 14:41  MistZero  阅读(11)  评论(0编辑  收藏  举报