2024牛客寒假算法基础集训营3

1|0A-智乃与瞩目狸猫、幸运水母、月宫龙虾


#include<bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; using i128 = __int128; using ldb = long double; #define int i64 using vi = vector<int>; using pii = pair<int, int>; using vii = vector<pii>; const int inf = INT_MAX, INF = 1e18; const int mod = 998244353; const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0}; using edge = array<int, 3>; i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int n; cin >> n; string a , b; for( int x , y ; n ; n -- ){ cin >> a >> b; x = a[0] , y = b[0]; if( x >= 'A' and x <= 'Z' ) x = x + 'a' - 'A'; if( y >= 'A' and y <= 'Z' ) y = y + 'a' - 'A'; if( x == y ) cout << "Yes\n"; else cout << "No\n"; } }

2|0B-智乃的数字手串


模二后,把序列按照连续相同进行分段,并且如果第一段和最后一段相同则要合并成一段,如果一共分成了cnt段,则整体可进行的操作次数就是n-cnt。但是要注意如果只有一段则可以进行n次操作。

#include<bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; using i128 = __int128; using ldb = long double; #define int i64 using vi = vector<int>; using pii = pair<int, int>; using vii = vector<pii>; const int inf = INT_MAX, INF = 1e18; const int mod = 998244353; const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0}; using edge = array<int, 3>; void solve() { int n; cin >> n; vi a(n); for (auto &i: a) cin >> i, i %= 2; int cnt = 1 , res ; for (int i = 1; i < n; i++) if (a[i] != a[i - 1]) cnt++; if (cnt > 2 and a.front() == a.back()) cnt--; if( cnt == 1 ) res = n; else res = n - cnt; if( res % 2 ) cout << "qcjj\n"; else cout << "zn\n"; return; } i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int TC; for (cin >> TC; TC; TC--) solve(); }

3|0C-智乃的前缀、后缀、回文


其实是是一个字符串模板题了算是,所以我用了两个字符串算法来求解。

首先用 Manacher 求出S串所有的前缀回文串和后缀回文串,然后用字符串哈希判断每一个S的前缀前缀是否与T的后缀相同,每一个S的后缀是否与T的前缀相同。

处理选择我先处理出后缀最大值,然后计算前缀的时候直接与后缀最大值一起更新答案即可。

#include <bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; using vi = vector<i64>; namespace Hash { // 下标从 1 开始 using Val = pair<i64, i64>; const Val Mod(1e9 + 7, 1e9 + 9); const Val base(13331, 23333); vector<Val> p; Val operator+(Val a, Val b) { i64 c1 = a.first + b.first, c2 = a.second + b.second; if (c1 >= Mod.first) c1 -= Mod.first; if (c2 >= Mod.second) c2 -= Mod.second; return pair(c1, c2); } Val operator-(Val a, Val b) { i64 c1 = a.first - b.first, c2 = a.second - b.second; if (c1 < 0) c1 += Mod.first; if (c2 < 0) c2 += Mod.second; return pair(c1, c2); } Val operator*(Val a, Val b) { return pair(a.first * b.first % Mod.first, a.second * b.second % Mod.second); } void init(int n) { p.resize(n + 1), p[0] = pair(1, 1); for (int i = 1; i <= n; i++) p[i] = p[i - 1] * base; return; } struct Hash { vector<Val> h; Hash(const string &s) { h.resize(s.size() + 1); for (int i = 1; i <= s.size(); i++) h[i] = h[i - 1] * base + pair(s[i - 1], s[i - 1]); return; } Val getHash(int l, int r) { if (l > r) return pair(0, 0); return h[r] - h[l - 1] * p[r - l + 1]; } Val val() { return h.back(); } }; } const int N = 1e5; string manacherInit(const string &s) { string t = "#"; for (const char &c: s) t += c, t += '#'; return t; } vector<int> manacher(const string &s) { int n = s.size(); vector<int> p(n); for (int i = 0, j = 0; i < n; i++) { if (j + p[j] > i) p[i] = min(p[j * 2 - i], j + p[j] - i); while (i >= p[i] and i + p[i] < n and s[i - p[i]] == s[i + p[i]]) p[i]++; if (i + p[i] > j + p[j]) j = i; } return p; } int main() { ios::sync_with_stdio(false), cin.tie(nullptr); Hash::init(N); int n, m; cin >> n >> m; string s, t; cin >> s >> t; if (n > m) swap(n, m), swap(s, t); auto p = manacher(manacherInit(s)); vi pm, sm; for (int i = 1; i < n; i++) { if (p[i] > i) pm.push_back(i); if (p[n * 2 - i] > i) sm.push_back(i); } Hash::Hash hs(s), ht(t); vi sufVal(n + 1, -1); for (auto len: sm) { if (ht.getHash(1, len) == hs.getHash(n - len + 1, n)) sufVal[n - len + 1] = len; } for (int i = n - 1; i >= 1; i--) sufVal[i] = max(sufVal[i], sufVal[i + 1]); i64 res = -1; for (auto len: pm) { if (sufVal[len + 1] == -1) break; if (hs.getHash(1, len) == ht.getHash(m - len + 1, m)) res = max(res, len + sufVal[len + 1]); } if (res > 0) cout << res * 2 << "\n"; else cout << "-1\n"; return 0; }

当然了,判断回文串也可以逆序哈希求解。

4|0D-chino's bubble sort and maximum subarray sum(easy version)


直接枚举交换的位置即可。

#include<bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; using i128 = __int128; using ldb = long double; #define int i64 using vi = vector<int>; using pii = pair<int, int>; using vii = vector<pii>; const int inf = INT_MAX, INF = 1e18; const int mod = 998244353; const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0}; using edge = array<int, 3>; i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int n, k; cin >> n >> k; vi a(n); for (auto &i: a) cin >> i; auto calc = [&a]() { int ans = -inf; for (int i = 0, cnt = 0; i < a.size(); i++) { cnt += a[i]; ans = max(ans, cnt); if (cnt < 0) cnt = 0; } return ans; }; if (k == 0) cout << calc() << "\n"; else { int res = -inf; for (int i = 1; i < n; i++) { swap(a[i - 1], a[i]); res = max(res, calc()); swap(a[i - 1], a[i]); } cout << res << "\n"; } }

5|0G-智乃的比较函数(easy version)


可以直接枚举三个数赋值

#include<bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; using i128 = __int128; using ldb = long double; #define int i64 using vi = vector<int>; using pii = pair<int, int>; using vii = vector<pii>; const int inf = INT_MAX, INF = 1e18; const int mod = 998244353; const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0}; using edge = array<int, 3>; void solve() { int n; cin >> n; vector<array<i32, 3>> b(n); for (auto &it: b) for (auto &i: it) cin >> i; vector<int> a(4); auto check = [&a, &b]() { for (const auto &[x, y, z]: b) if ((a[x] < a[y]) != z) return false; return true; }; for (a[1] = 0; a[1] <= 2; a[1]++) for (a[2] = 0; a[2] <= 2; a[2]++) for (a[3] = 0; a[3] <= 2; a[3]++) if (check()) { cout << "Yes\n"; return; } cout << "No\n"; } i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int TC; for (cin >> TC; TC; TC--) solve(); return 0; }

6|0H-智乃的比较函数(normal version)


同 G

7|0J-智乃的相亲活动


其实可以分开算每个女生不选某个男生的概率,分别累乘就可以计算出一个男生不被所有女生选中期望,然后就可以算出被选男生的数量的期望。女生同理。

#include<bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; using i128 = __int128; using ldb = long double; #define int i64 using vi = vector<int>; using pii = pair<int, int>; using vii = vector<pii>; const int inf = INT_MAX, INF = 1e18; const int mod = 998244353; const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0}; using edge = array<int, 3>; i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int n, m, k; cin >> n >> m >> k; vector<vi> manToFemale(n), femaleToMan(m); for (int x, y; k; k--) { cin >> x >> y, --x, --y; manToFemale[x].push_back(y); femaleToMan[y].push_back(x); } vector<ldb> notMan(n, 1.0), notFemale(m, 1.0); for (const auto &it: manToFemale) for (const auto &i: it) notFemale[i] *= (ldb) (it.size() - 1) / (it.size()); for (const auto &it: femaleToMan) for (const auto i: it) notMan[i] *= (ldb) (it.size() - 1) / (it.size()); ldb eMan = 0, eFemale = 0; for (const auto &i: notMan) eMan += 1.0 - i; for (const auto &i: notFemale) eFemale += 1.0 - i; cout << "float\n" << fixed << setprecision(10) << eMan << " " << eFemale << "\n"; return 0; }

8|0k-智乃的“黑红树”


构造起来还算简单,简单思路就是用两个队列分别进行 bfs。如果最后点凑不够就是无解。

#include<bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; using i128 = __int128; using ldb = long double; #define int i64 using vi = vector<int>; using pii = pair<int, int>; using vii = vector<pii>; const int inf = INT_MAX, INF = 1e18; const int mod = 998244353; const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0}; using edge = array<int, 3>; void solve() { int a, b, n;// black red cin >> a >> b, n = a + b; if( a == 0 ) { cout << "No\n"; return; } vector<vi> tree(n + 1, vi(2, -1)); queue<int> redLeaf, blackLeaf; blackLeaf.push(1), a--; for (int f = 0, t = 1, x; a + b > 0; f = 0) { while (not blackLeaf.empty() and b >= 2 and t + 2 <= n) { f |= 1, x = blackLeaf.front(), b -= 2, blackLeaf.pop(); tree[x][0] = ++t, redLeaf.push(t); tree[x][1] = ++t, redLeaf.push(t); } while (not redLeaf.empty() and a >= 2 and t + 2 <= n) { f |= 1, x = redLeaf.front(), a -= 2, redLeaf.pop(); tree[x][0] = ++t, blackLeaf.push(t); tree[x][1] = ++t, blackLeaf.push(t); } if (f == 0) break; } if (a + b > 0) { cout << "No\n"; return; } cout << "Yes\n"; for (int i = 1; i <= n; i++) { for (auto j: tree[i]) cout << j << " "; cout << "\n"; } return; } i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int TC; for (cin >> TC; TC; TC--) solve(); return 0; }

9|0L-智乃的36倍数(easy version)


直接暴力枚举就好

#include<bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; using i128 = __int128; using ldb = long double; #define int i64 using vi = vector<int>; using pii = pair<int, int>; using vii = vector<pii>; const int inf = INT_MAX, INF = 1e18; const int mod = 998244353; const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0}; using edge = array<int, 3>; i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int n; cin >> n; vi a(n); for( auto & i : a ) cin >> i; int res = 0; for( int i = 0 ; i < n ; i ++ ) for( int j = 0 ; j < n ; j ++ ){ if( i == j ) continue; if (a[j] < 10) { if ((a[i] * 10 + a[j]) % 36 == 0) res++; } else { if ((a[i] * 100 + a[j]) % 36 == 0) res++; } } cout << res << "\n"; return 0; }

10|0M-智乃的36倍数(normal version)


因为数字位数有限,可以计算每个数字在某个位置下模 36 的值,然后枚举低位的值和低位占的位数,然后既可以计算出高位的值,这样就可以统计方案数。

#include<bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; using i128 = __int128; using ldb = long double; #define int i64 using vi = vector<int>; using pii = pair<int, int>; using vii = vector<pii>; const int inf = INT_MAX, INF = 1e18; const int mod = 998244353; const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0}; using edge = array<int, 3>; i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int n, res = 0; cin >> n; vector cntA(20, vi(36)), cntB(20, vi(36)); for (int x, y; n; n--) { cin >> x, y = log10(x) + 1; cntA[y][x % 36]++; for (i128 i = 1, j = 10; i <= 19; i++, j *= 10) cntB[i][(i128(x) * j) % 36]++; i128 z = x; for (int i = 1; i <= y; i++) z = z * 10; z += x; if (z % 36 == 0) res--; } for (int i = 1; i <= 19; i++) for (int j = 0; j < 36; j++) res += cntA[i][j] * cntB[i][(36 - j) % 36]; cout << res << "\n"; return 0; }

__EOF__

本文作者PHarr
本文链接https://www.cnblogs.com/PHarr/p/18059672.html
关于博主:前OIer,SMUer
版权声明CC BY-NC 4.0
声援博主:如果这篇文章对您有帮助,不妨给我点个赞
posted @   PHarr  阅读(36)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
历史上的今天:
2023-03-07 SMU Spring 2023 Trial Contest Round 2
点击右上角即可分享
微信分享提示