Hint 1 随机化
平面上n 个点是毫无规律的,就算每个点问一次也只能问到3×75 个点,这个数远小于1500,想要让每个点地位平等,考虑随机。
Hint 2 从一个已知的三角形往里缩
相比包含特殊点的三角形,不包含的三角形其面积相对较小。而且包含特殊点的三角形内部一定有答案。如果问到一个包含特殊点的三角形,想法是往里缩,直到找到答案。
具体地,如果问到x−y−z 里面包含u,可能会考虑继续问x−y−u 或x−u−z 或u−y−z。这里有好几种选择,用随机数选。
| 12
 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
 
 | #include <bits/stdc++.h>using namespace std;
 
 mt19937_64 rnd(chrono::steady_clock::now().time_since_epoch().count());
 
 int main() {
 int J;
 cin >> J;
 
 while (J--) {
 int n;
 cin >> n;
 
 array<int, 3> x{ 1, 2, 3 };
 while (true) {
 cout << "? " << x[0] << ' ' << x[1] << ' ' << x[2] << endl;
 int u;
 cin >> u;
 if (u == 0) {
 cout << "! " << x[0] << " " << x[1] << " " << x[2] << endl;
 break;
 } else {
 int op = rnd() % 3;
 x[op] = u;
 }
 }
 }
 
 return 0;
 }
 
 | 
Hint 正难则反
如果直接算答案,需要找里面的最大矩形,然后扣掉,剩下的部分是若干个小矩形,越算越多,十分复杂。
倒着想,考虑把四个小区间合并成一个大区间,算减少了多少区间,减少了 3 倍的大区间数量。这样一直合并,直至不能合并时就是答案。
也可以这样想,找里面的最大矩形,不扣掉,而是拆成小一点的若干矩形,需要补上 3 倍的大区间数量。这样一直拆开大矩形,直至矩形大小为 1。用大小为 1 的正方形数量减去补上的数量就是答案。
| 12
 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
 
 | #include <bits/stdc++.h>
 using namespace std;
 using ll = long long;
 using uint = unsigned;
 using ull = unsigned long long;
 
 int main() {
 int J;
 cin >> J;
 
 while (J--) {
 int l1, r1, l2, r2;
 cin >> l1 >> r1 >> l2 >> r2;
 
 ull res = 0;
 for (int bit = 1; bit < 30; bit++) {
 int s = 1 << bit;
 int rr1 = r1 / s * s;
 int rr2 = r2 / s * s;
 int ll1 = (l1 + s - 1) / s * s;
 int ll2 = (l2 + s - 1) / s * s;
 if (ll1 >= rr1 || ll2 >= rr2) {
 continue;
 }
 res -= 3ull * (rr1 - ll1) / s * (rr2 - ll2) / s;
 }
 res += 1ull * (r1 - l1) * (r2 - l2);
 cout << res << endl;
 }
 
 return 0;
 }
 
 | 
Hint 环是假的,看成区间做区间 DP
直观上可以把环看作拱形桥。
从外向内考虑每个区间,如果选择u<v<w 构成三角形,那么可以继续在[u+1,v−1],[v+1,w−1] 中选择。
按类似区间 DP 的写法,先处理小区间,再向外扩张。具体转移见代码。
| 12
 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
 
 | #include <bits/stdc++.h>using namespace std;
 using ll = long long;
 
 int main() {
 int J;
 cin >> J;
 
 while (J--) {
 int n;
 cin >> n;
 
 vector<int> a(n);
 for (auto& x : a) {
 cin >> x;
 }
 
 vector dp(n, vector<ll>(n));
 for (int r = 0; r < n; r++) {
 for (int l = r; l >= 0; l--) {
 for (int i = l; i < r; i++) {
 if (i != l) {
 dp[l][r] = max(dp[l][r], 1ll * a[l] * a[i] * a[r] + dp[l + 1][i - 1] + dp[i + 1][r - 1]);
 }
 dp[l][r] = max(dp[l][r], dp[l][i] + dp[i + 1][r]);
 }
 }
 }
 cout << dp[0][n - 1] << endl;
 }
 
 return 0;
 }
 
 |