3月11日 Codeforces 实战记录。
A. Draw a Square 构成正方形,四个数相等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <bits/stdc++.h> #define int long long using namespace std;void solve () { vector<int >a (4 ); for (int i = 0 ; i < 4 ; i++) cin >> a[i]; cout << (*max_element (a.begin (), a.end ()) == *min_element (a.begin (), a.end ()) ? "Yes" : "No" ) << '\n' ; } signed main () { ios::sync_with_stdio (0 ); cin.tie (0 ); int t; cin >> t; while (t--) solve (); return 0 ; }
B. The Third Side 最优策略,每次选取两条边 $a,b$ 构造最长的第三边 $a + b - 1$ 即可,与操作顺序无关。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <bits/stdc++.h> #define int long long using namespace std;void solve () { int n; cin >> n; vector<int >a (n); for (int i = 0 ; i < n; i++) cin >> a[i]; cout << accumulate (a.begin (), a.end (), 0ll ) - (n - 1 ) << '\n' ; } signed main () { ios::sync_with_stdio (0 ); cin.tie (0 ); int t; cin >> t; while (t--) solve (); return 0 ; }
C. XOR and Triangle 当 $x$ 的二进制形式为 10...0
或 11...1
时,没有对应的 $y$ 满足条件。
否则,对应构造 01...1
即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <bits/stdc++.h> using namespace std;void solve () { int x; cin >> x; if (!(x & (x - 1 )) || !(x & (x + 1 ))){ cout << -1 << '\n' ; return ; } cout << (1 << (31 - __builtin_clz(x))) - 1 << '\n' ; } signed main () { ios::sync_with_stdio (0 ); cin.tie (0 ); int t; cin >> t; while (t--) solve (); return 0 ; }
D. Counting Points 给出了关键信息:半径之和为 $10^5$ 量级。
那么直接维护每一个 $x$ 坐标对应多少个整点即可。
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 #include <bits/stdc++.h> #define int long long using namespace std;void solve () { int n, m; cin >> n >> m; vector<int >x (n), r (n); for (int i = 0 ; i < n; i++) cin >> x[i]; for (int i = 0 ; i < n; i++) cin >> r[i]; map<int , int >mp; for (int i = 0 ; i < n; i++){ for (int u = - r[i]; u <= r[i]; u++){ mp[x[i] + u] = max (mp[x[i] + u], (int )sqrt (r[i] * r[i] - u * u)); } } int res = 0 ; for (auto &[k, y] : mp){ res += 1 + 2 * y; } cout << res << '\n' ; } signed main () { ios::sync_with_stdio (0 ); cin.tie (0 ); int t; cin >> t; while (t--) solve (); return 0 ; }
E. Empty Triangle 交互题。
当我们询问三角形 $abc$ 后,假设返回一个 $d$ 点,我们知道,三角形 $abd,\ adc,\ dbc$ 将原来的三角形分为了 3 个部分。我们随机选取一个,就能近似将内含的点数缩小到原来的 $\frac13$,75 次询问,剩下的点的个数期望为 $1500\times(\frac{1}{3})^{75}$,大概在 $10^{-33}$ 量级。基本上可以认为一定能找到 empty triangle 了。
(不准确的估算推导,单从数量级上认为方案完全可行。)
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 #include <bits/stdc++.h> using namespace std;void solve () { int n; cin >> n; random_device rd; mt19937 gen (rd()) ; uniform_int_distribution<> dis (0 , 2 ); vector<int >a (3 ); for (int i = 0 ; i < 3 ; i++) a[i] = n - i; auto query = [&](char op){ cout << op; for (auto &i : a){ cout << ' ' << i; } cout << '\n' ; cout.flush (); }; query ('?' ); int np; cin >> np; while (np) { a[dis (gen)] = np; query ('?' ); cin >> np; } query ('!' ); } signed main () { ios::sync_with_stdio (0 ); cin.tie (0 ); int t; cin >> t; while (t--) solve (); return 0 ; }
F. Counting Necessary Nodes 考虑分别从 $x$ 轴方向,$y$ 轴方向,将询问矩形划分为长度区间均满足 $[a\cdot2^k,(a+1)\cdot2^k]$ 的区间。
划分后,对于一块区域,若 $x$ 轴方向上长为 $u$,$y$ 轴方向上长为 $v$。由于 $u, v$ 均为 2 的幂次,按小的为正方形区块边长,就能划分出 $\dfrac{\max(u,v)}{\min(u,v)}$ 个区块了。
时间复杂度 $O(\log^2n)$。
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 #include <bits/stdc++.h> using namespace std;vector<int >lenx, leny; void query (int l, int r, int d, int u, vector<int >&len) { if (l <= d && r >= u){ len.emplace_back (u - d); return ; } if (l >= u || r <= d){ return ; } int m = d + u >> 1 ; query (l, r, d, m, len); query (l, r, m, u, len); } void solve () { lenx.clear (); leny.clear (); int l1, r1, l2, r2; cin >> l1 >> r1 >> l2 >> r2; query (l1, r1, 0 , 1 << 20 , lenx); query (l2, r2, 0 , 1 << 20 , leny); int res = 0 ; for (auto &i : lenx){ for (auto &j : leny){ res += max (i, j) / min (i, j); } } cout << res << '\n' ; } signed main () { ios::sync_with_stdio (0 ); cin.tie (0 ); int t; cin >> t; while (t--) solve (); return 0 ; }
G. Game With Triangles: Season 2 区间dp,根据最优子结构优化,专门写一篇讲讲。
$O(n^5)$ 解法:
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 #include <bits/stdc++.h> #define int long long using namespace std;void solve () { int n; cin >> n; vector<int >a (n + 1 ); for (int i = 1 ; i <= n; i++) cin >> a[i]; vector<vector<int >>dp (n + 2 , vector <int >(n + 2 )); for (int len = 3 ; len <= n; len++){ for (int l = 1 , r = len; r <= n; l++, r++){ for (int i = l; i + 2 <= r; i++){ for (int j = i + 1 ; j + 1 <= r; j++){ for (int k = j + 1 ; k <= r; k++){ dp[l][r] = max (dp[l][r], dp[l][i - 1 ] + dp[i + 1 ][j - 1 ] + dp[j + 1 ][k - 1 ] + dp[k + 1 ][r] + a[i] * a[j] * a[k]); } } } } } cout << dp[1 ][n] << '\n' ; } signed main () { ios::sync_with_stdio (0 ); cin.tie (0 ); int t; cin >> t; while (t--) solve (); return 0 ; }
正解 $O(n^3)$
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 #include <bits/stdc++.h> #define int long long using namespace std;void solve () { int n; cin >> n; vector<int >a (n + 1 ); for (int i = 1 ; i <= n; i++) cin >> a[i]; vector<vector<int >>dp (n + 2 , vector <int >(n + 2 )); for (int len = 3 ; len <= n; len++){ for (int l = 1 , r = len; r <= n; l++, r++){ for (int i = l + 1 ; i < r; i++){ dp[l][r] = max (dp[l][r], dp[l + 1 ][i - 1 ] + dp[i + 1 ][r - 1 ] + a[l] * a[i] * a[r]); } for (int i = l; i + 1 <= r; i++){ dp[l][r] = max (dp[l][r], dp[l][i] + dp[i + 1 ][r]); } } } cout << dp[1 ][n] << '\n' ; } signed main () { ios::sync_with_stdio (0 ); cin.tie (0 ); int t; cin >> t; while (t--) solve (); return 0 ; }