Description
有 \(n\) 个 \([0, 10^{18}]\) 之间随机的整数。可以提出两次询问,每次询问给出不超过 \(n-1\) 个二元组 \((x_i,y_i)\)。返回 \(a_{x_i}+a_{y_i}\) 从小到大排序的结果。
不能询问 \((i,i)\) 或者重复的无序对 \((i,j)\)。
要求按顺序返回这 \(n\) 个数。\(1\leq n\leq 500\)。
Solution
注意到 \(n\) 比较小,值域很大且随机,所以在询问得到可以大致通过加减操作确定其是什么,并且正确率很高。设 \(s(i,j)=a_i+a_j\)。
首先考虑如果知道 \(a_1,a_2\),怎么推出后面的数。
注意到 \(s(i-1,i)-s(2,i)=a_{i-1}-a_2\),所以如果已经推出 \(a_1,a_2,\ldots,a_{i-1}\),可以通过询问 \(\left\{(1,2),(2,3),\ldots,(n-1,n)\right\}\) 和 \(\left\{(2,3),(2,4),\ldots,(2,n-1)\right\}\) 并从中暴力枚举出满足条件的 \(s(i-1,i)\) 和 \(s(2,i)\),然后就可以通过 \(s(i-1,i)\) 和 \(a_{i-1}\) 来求出 \(a_i\)。
那么怎么知道一部分数的值呢。
由于上面的那个做法已经把两次询问都用上了,所以只能并行地去做一些询问来得到 \(a_1,a_2\)。
考虑确定前 \(4\) 个数。
先询问 \(\left\{(1,2),(1,3),(1,4),(4,5),(5,6),\ldots,(n-1,n)\right\}\) 和 \(\left\{(2,3),(3,4),(2,4),(2,5),(2,6),\ldots,(2,n)\right\}\)。
通过首先由于 \(s(1,2)+s(3,4)=s(1,3)+s(2,4)=s(1,4)+s(2,3)\),这里有 \(3\) 个相等的和,次数一定是最多的,所以可以以此求出 \(\left\{s(1,2),s(1,3),s(1,4)\right\}\) 和 \(\left\{s(2,3),s(3,4),s(2,4)\right\}\),然后就可以得到 \(a_1\) 和 \(\left\{a_2,a_3,a_4\right\}\)。同时通过之前的 \((4,5)\) 和 \((2,5)\) 可以得到 \(a_4-a_2\),所以可以以很大的概率确定 \(a_2,a_3,a_4\) 分别是哪个。
然后用上面的做法就可以得到后面的数了。
时间复杂度:\(O(n^3)\)。
Code
#include <bits/stdc++.h>#ifdef ORZXKR
#include "grader.cpp"
#endifusing i64 = long long;std::vector<i64> game(int n);
std::vector<i64> ask(std::vector<int> x,std::vector<int> y);std::vector<int> work(std::vector<int> vec) {for (auto &x : vec) --x;return vec;
}void del(std::vector<i64> &vec, i64 x) {std::vector<i64> ret;for (auto xx : vec)if (xx != x)ret.emplace_back(xx);vec = ret;
}std::pair<i64, i64> getpr(std::vector<i64> &vec1, std::vector<i64> &vec2, i64 x) {for (auto a : vec1)for (auto b : vec2)if (a - b == x)return {a, b};return {-1, -1};
}std::vector<i64> game(int n) {std::vector<i64> arr(n), res1, res2;std::vector<int> vec1, vec2, vec3, vec4;vec1 = {1, 1, 1}, vec2 = {2, 3, 4};for (int i = 4; i <= n - 1; ++i) vec1.emplace_back(i), vec2.emplace_back(i + 1);vec3 = {2, 3, 4}, vec4 = {3, 4, 2};for (int i = 5; i <= n; ++i) vec3.emplace_back(2), vec4.emplace_back(i);res1 = ask(work(vec1), work(vec2)), res2 = ask(work(vec3), work(vec4));// get a[1] and {a[2], a[3], a[4]}std::map<i64, std::vector<std::pair<i64, i64>>> mp;for (auto x : res1)for (auto y : res2)mp[x + y].emplace_back(x, y);std::vector<i64> v234;i64 mxv = -1, cc = 0;for (auto [x, vec] : mp) {if (vec.size() > cc) {mxv = x, cc = vec.size();}}i64 sum234 = 0;for (auto [x, y] : mp[mxv])arr[0] += x, sum234 += y, del(res1, x), del(res2, y);assert(sum234 % 2 == 0);sum234 /= 2;assert(arr[0] >= sum234 && (arr[0] - sum234) % 3 == 0);arr[0] = (arr[0] - sum234) / 3;for (auto [x, y] : mp[mxv]) v234.emplace_back(x - arr[0]);for (int i = 0; i < 3; ++i) {for (int j = 0; j < 3; ++j) {if (i == j) continue;auto pr = getpr(res1, res2, v234[i] - v234[j]);if (pr != std::pair<i64, i64>{-1, -1}) {arr[3] = v234[i], arr[1] = v234[j], arr[2] = v234[3 - i - j];}}}// std::cerr << arr[0] << ' ' << arr[1] << ' ' << arr[2] << ' ' << arr[3] << ' ';for (int i = 4; i < n; ++i) {auto pr = getpr(res1, res2, arr[i - 1] - arr[1]);// assert(pr != std::pair<i64, i64>{-1, -1});// assert(pr.first != -1 && pr.second != -1);del(res1, pr.first), del(res2, pr.second);arr[i] = pr.first - arr[i - 1];// std::cerr << arr[i] << ' ';}// std::cerr << '\n';return arr;
}