P3540 SQU-Squarks Sol

下面将可能的答案称为 a1,...,an

因为题目只给你 ai+aj,所以想到特殊的最小值、最大值。

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

考虑最小值,a1+a2,那么次小值也可以知道是 a1+a3

那么 a2+a3 呢?但是我们不知道第三小的值是 a1+a4 还是 a2+a3

所以想到枚举 a2+a3,那么就可以得到 a1,a2,a3 了。

接着我们就可以枚举剩下的最小值,一定是 a1+a4

由于知道了 a1,a2,a3,就可以得到 a4 的值。

接着把 a1+a4,a2+a4,a3+a4 从输入的数组中剔除,以此类推,可以得出答案。

那么枚举 a2+a3 时,发现只有 a1+ai 才可能 <a2+a3

因为 a1<a2,所以 a1+ai<a2+ai(3in)

从而有枚举最小的 n2 个数(除去 a1+a2a1+a3),依次钦定为 a2+a3 即可。

最后由于 ai+aj 可能有重复,所以枚举的 a2+a3 也会有重复,于是对答案进行去重才能过。

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

#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 @   MistZero  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示