牛客周赛 Round 60 (个人觉得比较舒服的一场)
1.牛客周赛 Round 60 (个人觉得比较舒服的一场)
2.牛客周赛 Round 63这场比较guess吧
A.困难数学题
题意:(数学)
计算x ^ x ^ x ^ x的值
思路:
根据异或的结论 x ^ x = 0 可代入式子得到最终结果为0
复杂度:
O(1)
Code:
1 2 | n = int ( input ()) print ( 0 ) |
知识点(拓展):
常用结论:
1 2 3 4 5 6 | 自反性: 对于任意a满足, a ^ a = 0 && a ^ 0 = a 交换性: 对于任意a 和 b满足, a ^ b = b ^ a 结合性: 对于任意a, b, c满足, (a ^ b) ^ c = a ^ (b ^ c) |
B.构造序列
题意:(贪心)
n 个正数 m个负数 正数不能和正数相邻,负数不能和负数相邻 最长能构造多长的序列
思路:
如果要实现最长的序列也就是正负交替实现,很快得到min(n, m) * 2 + (n != m)
复杂度:
O(1)
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #include <bits/stdc++.h> using namespace std; void solve() { int n, m; cin >> n >> m; cout << min(n, m) * 2 + (n != m) << '\n' ; } int main() { cin.tie(0) -> sync_with_stdio( false ); int t = 1; // cin >> t; while (t--) { solve(); } return 0; } |
C.连点成线
题意:(模拟)
给定一个 n * n 的棋盘和 m 个棋子,每个棋子的坐标为 (x[i], y[i])。如果两个棋子在同一行或同一列,可以连线。
求连上线后最长的那条线的长度,若没有连线则输出 0。
思路:
通过遍历棋子,记录每一行和每一列的最大值和最小值,然后根据这些值计算出最长的连线长度
复杂度:
O(n)
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 | #include <bits/stdc++.h> using namespace std; void solve() { int n, m; cin >> n >> m; vector < int > mi_x(n + 1, n + 1), mx_x(n + 1, 0), mi_y(n + 1, n + 1), mx_y(n + 1, 0); for ( int i = 0; i < m; i++) { int x, y; cin >> x >> y; mi_x[x] = min(mi_x[x], y); mx_x[x] = max(mx_x[x], y); mi_y[y] = min(mi_y[y], x); mx_y[y] = max(mx_y[y], x); } int ans = 0; for ( int i = 1; i <= n; i++) { if (mx_x[i] > mi_x[i]) { ans = max(ans, mx_x[i] - mi_x[i]); } if (mx_y[i] > mi_y[i]) { ans = max(ans, mx_y[i] - mi_y[i]); } } cout << ans << '\n' ; } int main() { cin.tie(0) -> sync_with_stdio( false ); int t = 1; // cin >> t; while (t--) { solve(); } return 0; } |
D.我们N个真是太厉害了
题意:(贪心 类似于硬币问题(覆盖问题))
判断几个人手中的 ai 个数能否相加表示 n 以内的任意正整数,若可以则输出 'Cool!',否则输出无法表示的最小正整数
思路:
通过依次遍历并累加满足 a[i] <= sum + 1 的星星数量,我们可以扩展可表示的整数范围为 [1, sum],直到找到某个 a[i] > sum + 1,此时 sum + 1 就是无法表示的最小整数
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 | #include <bits/stdc++.h> using namespace std; void solve() { int n; cin >> n; vector < int > a(n); for ( int &i : a) cin >> i; sort(a.begin(), a.end()); int cur = 0; for ( int i : a) { if (cur >= i - 1 && cur <= n) { cur += i; } } if (cur >= n) { cout << "Cool!\n" ; } else { cout << cur + 1 << '\n' ; } } int main() { cin.tie(0) -> sync_with_stdio( false ); int t = 1; cin >> t; while (t--) { solve(); } return 0; } |
E.折返跑
知识点传送门:https://www.cnblogs.com/BobHuang/p/14979765.html
题意:
将 m - 1 次推杆操作视为在 n - 2 个点的范围内移动,使得左杆和右杆始终保持不重合 保持合法问有多少种推法
思路:
结论为 C(n - 2, m - 1) 是因为问题等价于在 ( n - 2 ) 个点中选择 ( m - 1 ) 个位置进行推杆操作,计算出所有可能的合法推法
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 | #include <bits/stdc++.h> using namespace std; using i64 = int64_t; constexpr i64 mod = 1e9 + 7, maxn = 1e6 + 5; // 998244353 i64 inv[maxn], f[maxn]; i64 power (i64 a, i64 b) { i64 res = 1; for ( ; b > 0; b >>= 1, a = a * a % mod) { if (b & 1) res = res * a % mod; } return res; } void init () { inv[0] = f[0] = 1; for ( int i = 1; i < maxn; ++i) { f[i] = (f[i - 1] * i) % mod; inv[i] = power(f[i], mod - 2) % mod; } } i64 C( int n, int k) { return f[n] * inv[k] % mod * inv[n - k] % mod; } void solve() { int n, m; cin >> n >> m; cout << C(n - 2, m - 1) << '\n' ; } int main() { cin.tie(0) -> sync_with_stdio( false ); int t = 1; init(); cin >> t; while (t--) { solve(); } return 0; } |