P11647 【MX-X8-T6】「TAOI-3」俄罗斯蓝猫 题解

Description

nn[0,1018][0, 10^{18}] 之间随机的整数。可以提出两次询问,每次询问给出不超过 n1n-1 个二元组 (xi,yi)(x_i,y_i)。返回 axi+ayia_{x_i}+a_{y_i} 从小到大排序的结果。

不能询问 (i,i)(i,i) 或者重复的无序对 (i,j)(i,j)

要求按顺序返回这 nn 个数。1n5001\leq n\leq 500

Solution

注意到 nn 比较小,值域很大且随机,所以在询问得到可以大致通过加减操作确定其是什么,并且正确率很高。设 s(i,j)=ai+ajs(i,j)=a_i+a_j

首先考虑如果知道 a1,a2a_1,a_2,怎么推出后面的数。

注意到 s(i1,i)s(2,i)=ai1a2s(i-1,i)-s(2,i)=a_{i-1}-a_2,所以如果已经推出 a1,a2,,ai1a_1,a_2,\ldots,a_{i-1},可以通过询问 {(1,2),(2,3),,(n1,n)}\left\{(1,2),(2,3),\ldots,(n-1,n)\right\}{(2,3),(2,4),,(2,n1)}\left\{(2,3),(2,4),\ldots,(2,n-1)\right\} 并从中暴力枚举出满足条件的 s(i1,i)s(i-1,i)s(2,i)s(2,i),然后就可以通过 s(i1,i)s(i-1,i)ai1a_{i-1} 来求出 aia_i


那么怎么知道一部分数的值呢。

由于上面的那个做法已经把两次询问都用上了,所以只能并行地去做一些询问来得到 a1,a2a_1,a_2

考虑确定前 44 个数。

先询问 {(1,2),(1,3),(1,4),(4,5),(5,6),,(n1,n)}\left\{(1,2),(1,3),(1,4),(4,5),(5,6),\ldots,(n-1,n)\right\}{(2,3),(3,4),(2,4),(2,5),(2,6),,(2,n)}\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)s(1,2)+s(3,4)=s(1,3)+s(2,4)=s(1,4)+s(2,3),这里有 33 个相等的和,次数一定是最多的,所以可以以此求出 {s(1,2),s(1,3),s(1,4)}\left\{s(1,2),s(1,3),s(1,4)\right\}{s(2,3),s(3,4),s(2,4)}\left\{s(2,3),s(3,4),s(2,4)\right\},然后就可以得到 a1a_1{a2,a3,a4}\left\{a_2,a_3,a_4\right\}。同时通过之前的 (4,5)(4,5)(2,5)(2,5) 可以得到 a4a2a_4-a_2,所以可以以很大的概率确定 a2,a3,a4a_2,a_3,a_4 分别是哪个。

然后用上面的做法就可以得到后面的数了。

时间复杂度:O(n3)O(n^3)

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <bits/stdc++.h>

#ifdef ORZXKR
#include "grader.cpp"
#endif

using 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;
}

P11647 【MX-X8-T6】「TAOI-3」俄罗斯蓝猫 题解
https://sobaliuziao.github.io/2025/02/01/post/dba36031.html
作者
Egg_laying_master
发布于
2025年2月1日
许可协议