牛客周赛 Round 63
1.牛客周赛 Round 60 (个人觉得比较舒服的一场)
2.牛客周赛 Round 63
A.小红的好数
题意:
满足数位为2, 且个位数和十位数相等
思路:
通过输入字符串, 首先判断字符串的个数是否为2, 在判断个位数和十位数是否相等
复杂度:
O(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 | #include <bits/stdc++.h> using namespace std; using i64 = int64_t; void solve() { string s; cin >> s; if (s[0] == s[1] && s.size() == 2) { cout << "Yes\n" ; } else { cout << "No\n" ; } } int main() { cin.tie(0) -> sync_with_stdio( false ); int t = 1; // cin >> t; while (t--) { solve(); } return 0; } |
B.小红的好数组
题意:
找到区间为k长度的连续区间且不是回文数组但是可以修改一次得到回文数组, 计算当前满足回文数组条件的个数
思路:
直接暴力枚举长度为k的连续区间, 判断是否修改一次满足是回文数组
复杂度:
O(n * k)
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 | #include <bits/stdc++.h> using namespace std; using i64 = int64_t; void solve() { int n, k; cin >> n >> k; vector < int > a(n); for ( int i = 0; i < n; i++) { cin >> a[i]; } int ans = 0; for ( int i = 0; i <= n - k; i++) { vector < int > b(a.begin() + i, a.begin() + i + k); int cnt = 0; for ( int l = 0, r = k - 1; l < r; l ++, r --) { if (b[l] != b[r]) { cnt++; if (cnt > 1) { break ; } } } if (cnt == 1) { ans++; } } cout << ans << '\n' ; } int main() { cin.tie(0) -> sync_with_stdio( false ); int t = 1; // cin >> t; while (t--) { solve(); } return 0; } |
C.小红的矩阵行走
题意:
从(0, 0)出发, 只能走下或右且每走一步都收集数字, 走到(n - 1, 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 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 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | #include <bits/stdc++.h> using namespace std; using i64 = int64_t; constexpr int N = 1e2 + 5; int dirs[3] = {1, 0, 1}, n, m, a[N][N]; bool ok = 1; bool check ( int x, int y) { return x >= 0 && x < n && y >= 0 && y < m; } void dfs ( int x, int y) { if (x == n - 1 && y == m - 1) { ok = 0; return ; } for ( int i = 0; i < 2; i++) { int dx = dirs[i] + x, dy = dirs[i + 1] + y; if (check(dx, dy) && a[dx][dy] == a[0][0]) { dfs(dx, dy); } } } void solve() { cin >> n >> m; for ( int i = 0; i < n; i++) { for ( int j = 0; j < m; j++) { cin >> a[i][j]; } } ok = 1; dfs(0, 0); cout << (!ok? "Yes" : "No" ) << '\n' ; } int main() { cin.tie(0) -> sync_with_stdio( false ); int t = 1; cin >> t; while (t--) { solve(); } return 0; } #include <bits/stdc++.h> using namespace std; using i64 = int64_t; constexpr int N = 1e2 + 5; int dirs[3] = {1, 0, 1}, a[N][N], n, m; bool check ( int x, int y) { return x >= 0 && x < n && y >= 0 && y < n; } void solve() { cin >> n >> m; for ( int i = 0; i < n; i++) { for ( int j = 0; j < m; j++) { cin >> a[i][j]; } } queue <pair< int , int >> q; q.push({0, 0}); while (!q.empty()) { auto [x, y] = q.front(); q.pop(); if (x == n - 1 && y == m - 1) { cout << "Yes" << '\n' ; return ; } for ( int i = 0; i < 2; i++) { int dx = dirs[i] + x, dy = dirs[i + 1] + y; if (check(dx, dy) && a[dx][dy] == a[0][0]) { q.push({dx, dy}); } } } cout << "No" << '\n' ; } int main() { cin.tie(0) -> sync_with_stdio( false ); int t = 1; cin >> t; while (t--) { solve(); } return 0; } #include <bits/stdc++.h> using namespace std; using i64 = int64_t; constexpr int N = 1e2 + 5; int n, m, dp[N][N], a[N][N]; void solve() { cin >> n >> m; for ( int i = 1; i <= n; i++) { for ( int j = 1; j <= m; j++) { cin >> a[i][j]; dp[i][j] = 0; } } dp[1][1] = 1; for ( int i = 1; i <= n; i++) { for ( int j = 1; j <= m; j++) { if (i == 1 && j == 1) continue ; if (a[i][j] != a[1][1]) continue ; dp[i][j] = (i > 1 ? dp[i - 1][j] : 0) || (j > 1 ? dp[i][j - 1] : 0); } } cout << (dp[n][m] ? "Yes" : "No" ) << '\n' ; } int main() { cin.tie(0) -> sync_with_stdio( false ); int t = 1; cin >> t; while (t--) { solve(); } return 0; } |
D:小红的行列式构造
题意:
构造一个3阶行列式, 满足每个元素的绝对值不小于1, 且最后的值等于x
思路:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | [a, b, c] [d, e, f] [g, h, i] 公式 a * e * i + b * f * g + c * d * h - c * e * g - a * f * h - b * d * i -> a * (e * i - f * h) + b * (f * g - d * i) + c * (e * g - d * h) 假设a, b, c都是相同的, 及我们令他们为1 得到 -> e * i - f * h + f * g - d * i - e * g + d * h 如果继续假设d, e, f都相同, 这样导致了最终的结果为0, 也就是得到第一个结论 -> d * (h - i) + e * (i - g) + f * (g - h) 那么为了简单, 我们令d为2, e, f都为1, 那么我们可以得到 -> 2 * (h - i) + (i - g) + g - h 最终得到这个公式 -> h - i == x h - i = x 那么只要满足这个式子都可以, 那么我可以假设i = 101那么我的h就是x + 101 为什么不能是x + (值 < 101) 是因为行列式的值的绝对值需要大于等于x也就因为这, 最小情况只能是[g, x + 101 x] 其次发现g在这个式子是直接被约掉的, 那么 abs (g) >= 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 | #include <bits/stdc++.h> using namespace std; using i64 = int64_t; void solve() { int x; cin >> x; if (x == 0) { cout << "1 1 1\n1 1 1\n1 1 1\n" ; } else { cout << "1 1 1\n2 1 1\n" << 2 << ' ' << x * 2 << ' ' << x << '\n' ; } } int main() { cin.tie(0) -> sync_with_stdio( false ); int t = 1; // cin >> t; while (t--) { solve(); } return 0; } |
E.小红的 red 计数
题意:
给定一个字符串, 若干查询, 每一次查询翻转[l, r]的字符串, 在输出此时red为子串的个数是多少 (每次查询不会真正的翻转区间)
思路1(也是第一个思路):
线段树
维护区间r-e-d的各个组合的值, 得到red的总和sum, 在区间翻转的时候, 导致长度>=2的字符串受到了影响, red 和 der, ed和de, re和ed, 去维护失去和得到的最后就是最终的答案 得到公式
1 2 | sum - res1.red + res1.der - res1.re * res3.d + res1.er * res3.d - res2.r * res1.ed + res2.r * res1.de |
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 82 | #include <bits/stdc++.h> using namespace std; using i64 = int64_t; constexpr int N = 1e5 + 5; int n, q; string s; struct SegTree { i64 r, e, d, re, er, ed, de, red, der; } seg[N << 2]; // r e d re ed er de red der void pushup (SegTree &n1, SegTree &n2, SegTree &n3) { n1.r = n2.r + n3.r; n1.e = n2.e + n3.e; n1.d = n2.d + n3.d; n1.re = n2.re + n3.re + n2.r * n3.e; n1.er = n2.er + n3.er + n2.e * n3.r; n1.ed = n2.ed + n3.ed + n2.e * n3.d; n1.de = n2.de + n3.de + n2.d * n3.e; n1.red = n2.red + n3.red + n2.r * n3.ed + n2.re * n3.d; n1.der = n2.der + n3.der + n2.d * n3.er + n2.de * n3.r; } void build ( int l, int r, int rt) { if (l == r) { seg[rt] = {s[l] == 'r' , s[l] == 'e' , s[l] == 'd' , 0, 0, 0, 0, 0, 0}; return ; } int mid = (l + r) >> 1; build (l, mid, rt << 1); build (mid + 1, r, rt << 1 | 1); pushup (seg[rt], seg[rt << 1], seg[rt << 1 | 1]); } SegTree query ( int L, int R, int l, int r, int rt) { // [L, R] -> (1, n) if (L > R) return {0}; if (L <= l && R >= r) { return seg[rt]; } int mid = (l + r) >> 1; SegTree res1 = {0}, res2 = {0}; if (mid >= L) { res1 = query(L, R, l, mid, rt << 1); } if (mid < R) { res2 = query(L, R, mid + 1, r, rt << 1 | 1); } SegTree res3 = {0}; pushup (res3, res1, res2); return res3; } void solve() { cin >> n >> q; cin >> s; s = '$' + s; build (1, n, 1); i64 sum = query (1, n, 1, n, 1).red; while (q--) { int l, r; cin >> l >> r; SegTree res1 = query(l, r, 1, n, 1); // [l, r] SegTree res2 = query(1, l - 1, 1, n, 1); // [1, l - 1] SegTree res3 = query(r + 1, n, 1, n, 1); // [r + 1, n] // re er d // red der // r ed r de cout << sum - res1.red + res1.der - res1.re * res3.d + res1.er * res3.d - res2.r * res1.ed + res2.r * res1.de << '\n' ; ; } } int main() { cin.tie(0) -> sync_with_stdio( false ); int t = 1; // cin >> t; while (t--) { solve(); } return 0; } |