1.飞船扫描
BFS/DFS。
就是找 \(0\) 的联通块,但该联通块不能碰到边界,\(BFS/DFS\) 搜一下即可。
点击查看代码
#include <bits/stdc++.h>using i64 = long long;int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);int n,m;std::cin >> m >> n;std::vector ve(n, std::vector<int>(m));for(int i = 0; i < n; i += 1) {for(int j = 0; j < m; j += 1) {std::cin >> ve[i][j];}}const int u[] = {1, -1, 0, 0};const int v[] = {0, 0, 1, -1};int ans = 0;for(int i = 0; i < n; i += 1) {for(int j = 0; j < m; j += 1) {if(ve[i][j]) continue;bool ok = true;int cnt = 0;std::queue<std::array<int,2>> pq;pq.push({i, j});ve[i][j] = 1;while(pq.size()) {auto [x, y] = pq.front();pq.pop();cnt += 1;for(int k = 0; k < 4; k += 1) {int dx = x + u[k];int dy = y + v[k];if(dx < 0 || dy < 0 || dx >= n || dy >= m) {ok = false;continue;}if(ve[dx][dy] == 0) {ve[dx][dy] = 1;pq.push({dx, dy});}}}if(ok) {ans += cnt;}}}std::cout << ans << "\n";return 0;
}
2.助手招募
模拟。
\(O(n^3)\) 枚举每个团队,判一下组成的人员中是否存在数值重复即可。
点击查看代码
#include <bits/stdc++.h>using i64 = long long;int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);int n;std::cin >> n;std::vector has(3, std::vector<std::array<int,5>>());for(int i = 0; i < n; i += 1) {int id, t, r1, r2, r3, r4;std::cin >> id >> t >> r1 >> r2 >> r3 >> r4;has[--t].push_back({id, r1, r2, r3, r4});}int vis[101] {};std::vector<std::array<int,3>> ans;for(int i = 0; i < has[0].size(); i += 1) {for(int p = 1; p < 5; p += 1) {vis[has[0][i][p]] += 1;}for(int j = 0; j < has[1].size(); j += 1) {bool ok = true;for(int p = 1; p < 5; p += 1) {if(vis[has[1][j][p]] && has[1][j][p]) ok = false;vis[has[1][j][p]] += 1;}if(ok) {for(int k = 0; k < has[2].size(); k += 1) {ok = true;for(int p = 1; p < 5; p += 1) {if(vis[has[2][k][p]] && has[2][k][p]) {ok = false;break;}}if(ok) {ans.push_back({has[0][i][0], has[1][j][0], has[2][k][0]});}}}for(int p = 1; p < 5; p += 1) {vis[has[1][j][p]] -= 1;}}for(int p = 1; p < 5; p += 1) {vis[has[0][i][p]] -= 1;}}if(ans.empty()) {std::cout << "-1\n";} else {sort(ans.begin(), ans.end());for(auto &[x, y, z] : ans) {std::cout << x << " " << y << " " << z << "\n";}}return 0;
}
3.能量共振
思维。
把前缀和出现的最近的坐标记录一下,如果当前的前缀和 \(sum\) 在之前出现过,记 \(lst\) 为上次 \(sum\) 出现的位置,那么说明 \(lst + 1\sim i\) 之间的加起来又刚好为 \(0\) 了,所以 \(sum\) 才又出现,那么 \(i-lst\) 就是当前 \(i\) 最短的和为 \(0\) 的子数组,记 \(f_i = i-lst\),那么如果 \(f_{i-f_i}\) 也存在的话,那这两就构成可对称分割数组,更新一下答案即可。
点击查看代码
#include <bits/stdc++.h>using i64 = long long;int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);int n;std::cin >> n;std::vector<int> a(n);for(int i = 0; i < n; i += 1) {std::cin >> a[i];}std::map<int,int> mp;mp[0] = -1;int ans = n, num = 0;i64 sum = 0;std::vector<int> f(n);for(int i = 0; i < n; i += 1) {sum += a[i];if(mp.count(sum)) {f[i] = i - mp[sum];if(i - f[i] >= 0 && f[i - f[i]]) {int x = f[i] + f[i - f[i]];if(x < ans) {ans = x;num = 1;} else if(x == ans) {num += 1;}}}mp[sum] = i;}if(!num) {std::cout << "-1 -1\n";} else {std::cout << ans << " " << num << "\n";}return 0;
}