1 条题解
-
0
自动搬运
来自洛谷,原作者为

Alex_Wei
**搬运于
2025-08-24 21:50:00,当前版本为作者最后更新于2021-12-19 22:32:18,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
将给出的 和要求的 都从大到小排序,,,这一点显然。
先考虑已知一些数时,如何推出剩下来的数:假设 已知,它们两两相加可以形成一些和 ,用可重集 减去可重集 ,我们能得到一个最大数 ,它只能是 的和,否则与 的最大性违背。
因此,我们断言如果确定 ,那么可以在 的时间内得到整个 :找到可重集 ( 的定义如上)中最大的数 ,反推出 ,用 与 的和更新 ,再找到下一个最大的 反推出 ,以此类推。根据 的单调性可以用指针维护 。 由用 通过
map打标记产生(代码用了priority_queue)。特别的,若求出的 或 或 则钦定的 无解。接下来考虑如何求 :注意到 仅有可能小于 ,因此 在从大到小排过序后的 中下标不会超过 。考虑直接枚举这个下标从而解出 和 。
综上,时间复杂度三方对数。由于大部分下标很快无解,因此常数非常小。
const int N = 300 + 5; int n, m, a[N * N >> 1]; uint mp[N * N * 35]; void s(int x) {mp[x >> 5] |= 1u << (x & 31);} bool query(int x) {return mp[x >> 5] >> (x & 31) & 1;} vector <vint> ans; int main(){ cin >> n, m = n * (n - 1) >> 1; for(int i = 1; i <= m; i++) a[i] = read(), s(a[i]); sort(a + 1, a + m + 1), reverse(a + 1, a + m + 1); for(int i = 3; i <= n; i++) if(i == 3 || a[i] != a[i - 1]) { static int x[N], sum; sum = a[1] + a[2] + a[i]; if(sum & 1) continue; x[1] = (sum >> 1) - a[i]; if(x[1] < n) continue; priority_queue <int> q; bool ok = 1; for(int j = 2, p = 1; j <= n && ok; j++) { while(!q.empty() && q.top() == a[p]) q.pop(), p++; x[j] = a[p] - x[1]; if(x[j] >= x[j - 1] || x[j] < 0) ok = 0; for(int k = 1; k < j && ok; k++) ok &= query(x[k] + x[j]), q.push(x[k] + x[j]); } if(ok) {vint p; for(int j = n; j; j--) p.pb(x[j]); ans.pb(p);} } cout << ans.size() << endl, rev(ans); for(vint it : ans) {for(int p : it) cout << p << " "; cout << endl;} return flush(), 0; }
- 1
信息
- ID
- 2616
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者