SMU Autumn 2024 Personal Round 2
SMU Autumn 2024 Personal Round 2
A. Not Adjacent Matrix
思路
可以按照奇数列就向上移动一个元素,溢出的元素补到最后一行,这样构造后检查一下是否有相邻元素即可(事实上只有 \(n=1\) 才会无解)。
代码
#include <bits/stdc++.h> using namespace std; using i64 = long long; void solve() { int n; cin >> n; vector a(n + 1, vector<int>(n + 1)); for (int i = 1; i <= n; i ++) { for (int j = 1; j <= n; j ++) { a[i][j] = (i - 1) * n + j; } } for (int i = 1; i <= n; i ++) { if (i & 1) { auto t = a[1][i]; for (int j = 2; j <= n; j ++) { a[j - 1][i] = a[j][i]; } a[n][i] = t; } } for (int i = 1; i <= n; i ++) { for (int j = 1; j < n; j ++) { if (a[i][j] == a[i][j + 1] + 1 || a[i][j] == a[i][j + 1] - 1) { cout << -1 << '\n'; return ; } } } for (int i = 1 ; i <= n; i ++) for (int j = 1; j <= n; j ++) cout << a[i][j] << " \n"[j == n]; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { solve(); } return 0; }
B. Alyona and Numbers
思路
要求 $(x+y) \equiv0\pmod{5} $ 的数量,其实只要看 \(x,y\) 的余数互补情况即可。
代码
#include <bits/stdc++.h> using namespace std; using i64 = long long; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n, m; cin >> n >> m; int M[6] {}; for (int i = 1; i <= m; i ++) { M[i % 5]++; } i64 ans = 0; for (int i = 1; i <= n; i ++) { ans += M[(5 - (i % 5)) % 5]; } cout << ans << '\n'; return 0; }
C. Pleasant Pairs
思路
将 \(a_i\)从小到大排序,然后暴力枚举数对匹配即可,当 \(a_i \times a_j \ge 4\times 10^5\) 时退出即可。
复杂度 \(O(nlogn)\)。
因为对于 \(a_i=1\),最多匹配 \(\frac {4\times 10 ^ 5}{1}\) 次,\(a_i = 2\),最多匹配 \(\frac {4\times 10 ^ 5}{2}\) 次,\(\dots\),对于 \(a_i=k\),最多匹配 \(\frac {4\times 10 ^ 5}{k}\) 次,即不会跑满 \(O(n^2)\),近似 \(O(nlogn)\) 。
代码
#include <bits/stdc++.h> using namespace std; using i64 = long long; void solve() { int n; cin >> n; vector<array<i64, 2>> a(n + 1); for (int i = 1; i <= n; i ++) { i64 x; cin >> x; a[i] = {x, i}; } sort(a.begin() + 1, a.end()); i64 ans = 0; for (int i = 1; i <= n; i ++) { auto [x, xi] = a[i]; for (int j = 1; j < i; j ++) { auto [y, yi] = a[j]; if (x * y > 2 * n) break; if (x * y == xi + yi) { ans ++; } } } cout << ans << '\n'; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { solve(); } return 0; }
D. Hossam and Friends
思路
双指针维护题目所说的区间,对于一个新的 \(r\) ,判断能不能扩展到它,可以用 \(multiset\) 维护朋友关系,如果存在该关系,则可以扩展到它,否则就停止。
代码
#include <bits/stdc++.h> using namespace std; using i64 = long long; void solve() { int n, m; cin >> n >> m; vector g(n + 1, vector<int>()); for (int i = 1; i <= m; i ++) { int u, v; cin >> u >> v; if (u > v) swap(u, v); g[u].push_back(v); } i64 ans = 0; multiset<int> s; for (int l = 1, r = 0; l <= n; l ++) { while (r + 1 <= n && !s.count(r + 1)) { r ++; for (auto v : g[r]) { s.insert(v); } } i64 len = r - l + 1; ans += len; for (auto v : g[l]) { s.erase(s.lower_bound(v)); } } cout << ans << '\n'; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { solve(); } return 0; }
E. Same Count One
思路
首先记所有 \(1\) 的数量为 \(num\),那么显然有当 \(n\mod num≠0\) 时无解。那么考虑有解的时候该怎么办。
显然对于每一个 \(a_i\) 序列中,最终 \(1\) 的数量为 $num $,记作 \(t\);并记 \(cnt_i\) 表示 \(a_i\) 序列中 \(1\) 的数量。
我们希望最终所有的 \(cnt_i\) 都等于 \(t\),并且希望操作步数最小,我们考虑一个显然的贪心:将 \(cnt_i>t\) 的序列中的 \(1\) 补 \(cnt_j<t\) 缺失的 \(1\)。
这样我们每一次的操作都会使 \(∑_{i=1}^n|cnt_i−t|\) 减少 \(2\),显然是最优的方案。
该题解转载:https://www.cnblogs.com/WaterSunHB/p/17962528/CF1774D
代码
#include <bits/stdc++.h> using namespace std; using i64 = long long; void solve() { int n, m; cin >> n >> m; int cnt = 0; vector bnariy(n, vector<int>(m)); vector<int> one(n); for (int i = 0; i < n; i ++) { for (int j = 0; j < m; j ++) { cin >> bnariy[i][j]; one[i] += bnariy[i][j] == 1; } cnt += one[i]; } if (cnt % n != 0) { cout << -1 << '\n'; return ; } int avg = cnt / n; vector<array<int, 3>> ans; for (int j = 0; j < m; j ++) { vector<int> has, need; for (int i = 0; i < n; i ++) { if (one[i] > avg && bnariy[i][j]) { has.emplace_back(i); } else if (one[i] < avg && !bnariy[i][j]) { need.emplace_back(i); } } while (has.size() && need.size()) { auto x = has.back(), y = need.back(); ans.push_back({x + 1, y + 1, j + 1}); one[x] --, one[y] ++; has.pop_back(), need.pop_back(); } } cout << ans.size() << '\n'; for (auto [x, y, z] : ans) { cout << x << ' ' << y << ' ' << z << '\n'; } } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { solve(); } return 0; }
F. Shuffling Songs
思路
状压DP。
不过我用并查集减掉了很多不合法的状态,比如它不是个连通块。
然后就是把状态中的点拿出来,如果存在边则连上,最后对存在的点做状压DP即可。
代码
#include <bits/stdc++.h> using namespace std; using i64 = long long; struct DSU { std::vector<int> f, siz; DSU() {} DSU(int n) { init(n); } void init(int n) { f.resize(n); std::iota(f.begin(), f.end(), 0); siz.assign(n, 1); } int find(int x) { while (x != f[x]) { x = f[x] = f[f[x]]; } return x; } bool same(int x, int y) { return find(x) == find(y); } bool merge(int x, int y) { x = find(x); y = find(y); if (x == y) { return false; } siz[x] += siz[y]; f[y] = x; return true; } int size(int x) { return siz[find(x)]; } }; void solve() { int n; cin >> n; int cnt = 0; unordered_map<string, int> mp; vector<pair<int, int>> a; for (int i = 0; i < n; i ++) { string s1, s2; cin >> s1 >> s2; if (!mp.count(s1)) { mp[s1] = ++cnt; } if (!mp.count(s2)) { mp[s2] = ++cnt; } a.emplace_back(mp[s1], mp[s2]); } vector edge(n, vector<int>(n)); for (int i = 0; i < n; i ++) { auto [s1, s2] = a[i]; for (int j = 0; j < i; j ++) { auto [w1, w2] = a[j]; if (s1 == w1 || s2 == w2) { edge[i][j] = edge[j][i] = 1; } } } int ans = n - 1; for (int i = 0; i < (1 << n); i ++) { if (__builtin_popcount(i) >= ans) { continue; } vector<int> now; for (int j = 0; j < n; j ++) { if (i >> j & 1) continue; now.emplace_back(j); } int m = n - __builtin_popcount(i); vector g(m, vector<int>()); DSU d(m); for (int j = 0; j < m; j ++) { for (int p = 0; p < m; p ++) { if (edge[now[j]][now[p]]) { g[j].emplace_back(p); g[p].emplace_back(j); d.merge(j, p); } } } if (d.size(0) != m) { continue; } const int inf = 100; vector dp(1 << m, vector<int>(m, inf)); for (int j = 0; j < m; j ++) { dp[1 << j][j] = 1; } auto check = [&](int st)->bool{ for (int k = 0; k < m; k ++) { if (st >> k & 1) { for (auto p : g[k]) { if (!(st >> p & 1)) { auto nst = st | (1 << p); dp[nst][p] = min(dp[nst][p], dp[st][k] + 1); if (nst == (1 << m) - 1 && dp[nst][p] == m) { ans = __builtin_popcount(i); return true; } } } } } return false; }; for (int st = 0; st < (1 << m); st ++) { if (check(st)) { break; } } } cout << ans << '\n'; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { solve(); } return 0; }
本文作者:Ke_scholar
本文链接:https://www.cnblogs.com/Kescholar/p/18523940
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步