CF1624D – Finding Zero – 题解与思路重现

给大家表演一个一场下青

CodeForces Round 770 Div.2 Problem D – Finding Zero

一道非常有意思的交互和构造题。

考虑能否固定两个数x,yx, y,通过它们的相对大小关系,确定其他数中是否存在00或最大值amaxa_{\text{max}}

经过一番推导,我们发现,设xyx \geq y的情况下,对于三元组(ai=x,aj=y,ak=z)(a_i=x, a_j=y, a_k=z),有g(i,j,k)=max(ai,aj,ak)min(ai,aj,ak)={zy,z>xxy,z[y,x]xz,z<yg(i, j, k)\newline =\max(a_i, a_j, a_k) – \min(a_i, a_j, a_k)= \begin{cases}z-y, & z > x \\ x-y, & z \in [y, x]\\ x-z, & z < y\end{cases}。所以,设x=6,y=4x=6, y=4以上式结果为因变量,zz为自变量,应有以下图像:

容易发现,在给定的aa序列当中取zz,当gg取到最大值时,zz00或者amaxa_{\text{max}}。令x=max(a1,a2),y=min(a1,a2)x=\max(a_1, a_2), y=\min(a_1, a_2)。现在我们就已经知道了数列中其中一个最值的位置。那么,如何判别这是amaxa_{\text{max}}还是00呢?

设该最值的位置为pp。容易发现,不论apa_pamaxa_{\text{max}}还是00,设qq为另一个最值的位置,则有max(ai,aj,ap)min(ai,aj,ap),pi,pj\max(a_i, a_j, a_p) – \min(a_i, a_j, a_p), p \neq i, p\neq jj=qj=qi=qi=q时取到最大值,否则与题设和定义相矛盾。同时,由于题目要求输出至多两个可能存在00的位置,我们需要更准确地判定另一个最值的位置。则我们枚举ii,令j=imodn+1j=i \mod n+1,计算g(i,j,p)g(i, j, p),则由于g(q1,q,p)g(q-1, q, p)g(q,q+1,p)g(q, q+1, p)两个结果均会取到最大值,故我们可以由此确定qq的位置。这时答案就是(p,q)(p, q)

还有一个比较棘手的问题:当i,j,3i<jn,g(1,2,i)=g(1,2,j)\forall i, j, 3 \leq i < j \leq n, g(1, 2, i)=g(1, 2, j)怎么办?一开始(赛时)我采取分类讨论的想法,发现出现这种情况,只可能是因为

  1. x,yx, y中既包含amaxa_{\text{max}}又包含00(下图粉红色点集);
  2. x,yx, y中包含00,且i[3,n],ai=amax\forall i \in [3, n], a_i=a_{\text{max}}(下图绿色点集);
  3. x,yx, y中不包含00,但i[3,n],(ai>xaiy=constant)(ai<yxai=constant)\forall i \in [3, n], (a_i>x \wedge a_i-y=\text{constant})\vee(a_i<y \wedge x-a_i=\text{constant})(下图浅蓝色点集)。

 

为什么不包含“xxamaxa_{\text{max}}y0y\neq 0”的情况?因为这样一来,由题意可得a3=a4==an=0a_3=a_4=\dots=a_n=0,与题设相矛盾。

再来考虑有什么办法能够将这三种情况统一起来。最开始,我考虑选出x,y,z,cx, y, z, c,分别计算g(x,y,c),g(x,z,c),g(y,z,c)g(x, y, c), g(x, z, c), g(y, z, c),然后取gg的最小值,认为其补集就是最值所在位置(例如,若g(x,z,c)g(x, z, c)取到最小,则yy是最值)。但这种方法在第三种情况会出问题。

但今天我发现,这三种情况有一个共性:最大值和最小值紧挨在一起,即pq=1|p-q|=1pq=n1|p-q|=n-1第一种情况无需证明;对于情况二,无论a1=0a_1=0还是a2=0a_2=0,都有an=amax=a3a_n=a_{\text{max}}=a_3;第三种情况,容易证明i[3,n],ai=amaxai=0\forall i \in [3, n], a_i = a_{\text{max}} \vee a_i=0。所以,我们直接计算所有三元组g(i,imodn+1,(i+1)modn+1),i[1,n]g(i, i \mod n + 1, (i + 1)\mod n+1), i \in [1, n],找到gg的最大值,和上述一种情况一样选择产生gp=gp+1=gmaxg_p=g_{p+1}=g_{\text{max}}pp,计算ppp+1p+1代表的三元组的交集即可。

总体来看,对于情况A,我们使用了(n2)+(n1)=2n3(n-2)+(n-1)=2n-3次询问;情况B则采用了恰好2n22n-2次询问。

实现时应当注意各种细节。Submission #145491065

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
  51. 51
  52. 52
  53. 53
  54. 54
  55. 55
  56. 56
  57. 57
  58. 58
  59. 59
  60. 60
  61. 61
  62. 62
  63. 63
  64. 64
  65. 65
  66. 66
  67. 67
  68. 68
  69. 69
  70. 70
  71. 71
  72. 72
  73. 73
  74. 74
  75. 75
  76. 76
  77. 77
  78. 78
  79. 79
  80. 80
  81. 81
  82. 82
  83. 83
  84. 84
  85. 85
  86. 86
  87. 87
  88. 88
  89. 89
  90. 90
  91. 91
  92. 92
  93. 93
  94. 94
  95. 95
  96. 96
  97. 97
  98. 98
  99. 99
  100. 100
  101. 101
  102. 102
#include <bits/stdc++.h> using namespace std; template <typename T> inline bool read (T &x) { x = 0; int f = 1; char c = getchar (); for (; c != EOF && !isdigit (c); c = getchar ()) if (c == '-') f = -1; if (c == EOF) return 0; for (; c != EOF && isdigit (c); c = getchar ()) x = (x<<1) + (x<<3) + (c^48); x *= f; return 1; } template <typename T, typename... Targs> inline bool read (T &x, Targs&... args) { return read (x) && read (args...); } template <typename T> void print (T x) { if (x < 0) putchar ('-'), x = -x; if (x > 9) print (x / 10); putchar ('0' + x % 10); } template <typename T, typename... Targs> inline void print (T x, Targs... args) { print (x), putchar (' '), print (args...); } #define reint register int #define inl inline #define newl putchar('\n') typedef long long ll; typedef unsigned long long ull; // typedef __int128 lll; typedef pair <int, int> pint; constexpr int N = 1024; int T, n, keko[N], pos[N][2], mx, mxfr; bool f, out; int tot; inl int publ (int a[2], int b[2]) { int g[4] = { a[0], a[1], b[0], b[1] }; sort (g, g + 4); for (int i = 1; i < 4; ++i) if (g[i] == g[i - 1]) return g[i]; } inl int ask (int i, int j, int k) { printf ("? %d %d %d\n", i, j, k); fflush (stdout); int res; scanf ("%d", &res); return fflush (stdout), res; } #define outp(x, y) (printf ("! %d %d\n", x, y), fflush (stdout)) #define proc(x) ((((x) - 1) + n) % n + 1) int main () { /* CF1634D Finding Zero 吴秋实 */ read (T); while (T--) { read (n); f = 1; mx = -1; out = tot = 0; for (int i = 3; i <= n; ++i) keko[i] = ask (1, 2, i); for (int i = 3; i <= n; ++i) { if (i > 3 && keko[i - 1] != keko[i]) f = 0; if (keko[i] > mx) mxfr = i, mx = keko[i]; } if (f) { for (int i = 1; i <= n - 2; ++i) keko[i] = ask (i, i + 1, i + 2); keko[n - 1] = ask (n - 1, n, 1); keko[n] = ask (n, 1, 2); mx = -1; for (int i = 1; i <= n; ++i) mx = max (mx, keko[i]); for (int i = 1; i <= n; ++i) if (keko[i] == mx && keko[proc (i + 1)] == mx) { outp (proc (i + 1), proc (i + 2)); out = 1; break; } if (!out) outp (1, 2); continue; } for (int i = 1; i <= n; ++i) { if (i == mxfr) continue; ++tot; if (i == proc (mxfr - 1)) pos[tot][0] = i, pos[tot][1] = proc (mxfr + 1); else pos[tot][0] = i, pos[tot][1] = proc (i + 1); keko[tot] = ask (mxfr, pos[tot][0], pos[tot][1]); } mx = -1; for (int i = 1; i <= tot; ++i) mx = max (mx, keko[i]); for (int i = 1; i <= tot; ++i) { int pre = i - 1 ? i - 1 : tot; if (keko[i] == mx && keko[pre] == mx) { outp (mxfr, publ (pos[i], pos[pre])); out = 1; break; } } if (!out) outp (1, 2); } return 0; }
  • 2022年2月7日