2024 ICPC ShaanXi Provincial Contest

1|0A. chmod


模拟

#include <bits/stdc++.h> using namespace std; using i64 = long long; void solve() { string s; cin >> s; int a = s[0] - '0', b = s[1] - '0', c = s[2] - '0'; if (a & 4) cout << "r"; else cout << "-"; if (a & 2) cout << "w"; else cout << "-"; if (a & 1) cout << "x"; else cout << "-"; if (b & 4) cout << "r"; else cout << "-"; if (b & 2) cout << "w"; else cout << "-"; if (b & 1) cout << "x"; else cout << "-"; if (c & 4) cout << "r"; else cout << "-"; if (c & 2) cout << "w"; else cout << "-"; if (c & 1) cout << "x"; else cout << "-"; cout << "\n"; } int main() { ios::sync_with_stdio(false), cin.tie(nullptr); int T; cin >> T; while (T--) solve(); return 0; }

2|0B. Expression Matrix


搜索,首先要尽可能多的使用符号,所以可以dp 出放置符合最多的方案。

然后搜索枚举每一个符号是加还是乘。

考虑一个剪枝优化,只有当符号所在的行或列存在两个11的时候才能使用加,否则只能使用乘

#include <bits/stdc++.h> using namespace std; using i32 = int; using i64 = long long; #define int i64 using vi = vector<int>; using pii = pair<int, int>; const int INF = LLONG_MAX / 2; i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int n, m; cin >> n >> m; vector f(n + 1, vi(m + 1)); int T = 0; vector<pii> opt; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { if (i == 1 or j == 1 or i == n or j == m) f[i][j] = 1; else if (f[i - 1][j] == 1 and f[i][j - 1] == 1) f[i][j] = -(T++), opt.emplace_back(i, j); else f[i][j] = 1; } vector<vi> r(n + 1); for (int i = 1, pre; i <= n; i++) { pre = 0; for (int j = 1; j <= m; j++) { if (f[i][j] == 1) pre = pre * 10 + 1; else r[i].push_back(pre), r[i].push_back(f[i][j]), pre = 0; } r[i].push_back(pre); } vector<vi> c(m + 1); for (int j = 1, pre; j <= m; j++) { pre = 0; for (int i = 1; i <= n; i++) { if (f[i][j] == 1) pre = pre * 10 + 1; else c[j].push_back(pre), c[j].push_back(f[i][j]), pre = 0; } c[j].push_back(pre); } vi cntR(n + 1); for (int i = 1; i <= n; i++) for (auto j: r[i]) if (j == 11) cntR[i]++; vi cntC(m + 1); for (int j = 1; j <= m; j++) for (auto i: c[j]) if (i == 11) cntC[j]++; vi op(T), res; int ans = INF; auto calc = [&](const vi &v) -> int { vi x; for (int i: v) { if (i > 0) x.push_back(i); else if (op[-i] == 0) x.push_back(-1); } vi y; for (int i = 0; i < x.size(); i++) { if (x[i] > 0) y.push_back(x[i]); else i++, y.back() *= x[i]; } return accumulate(y.begin(), y.end(), 0ll); }; auto dfs = [&](auto dfs, int i) -> void { if (i == T) { int sum = 0; for (int i = 1; i <= n; i++) sum += calc(r[i]); for (int j = 1; j <= m; j++) sum += calc(c[j]); if (sum < ans) ans = sum, res = op; return; } auto [ix, iy] = opt[i]; if (cntR[ix] >= 2 or cntC[iy] >= 2) { op[i] = 1; dfs(dfs, i + 1); } op[i] = 0; dfs(dfs, i + 1); }; dfs(dfs, 0); for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { if (f[i][j] == 1) cout << 1; else cout << "*+"[res[-f[i][j]]]; } cout << "\n"; } return 0; }

3|0C. Seats


这到题目,把iai连一条有向边,图就是内向基环树森林,其中有两种,一种是链,且最后一个点一定是空节点,此时链上所有点均可满足。另一种是内向基环树,此时只有环上的点可以满足。

所以可以用拓扑序求出链的长度,并且拓扑序没有入队的点就是环上的点。

#include <bits/stdc++.h> using namespace std; using i32 = int; using i64 = long long; using vi = vector<int>; using pii = pair<int, int>; i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int n; cin >> n; int N = n * 2; vector<vi> e(N + 1); vi vis(N + 1), dis(N + 1), deg(N + 1); for (int i = 1, x; i <= n; i++) cin >> x, e[i].push_back(x), deg[x]++; queue<int> q; for (int i = 1; i <= N; i++) if (deg[i] == 0) q.push(i); while (not q.empty()) { int x = q.front(); vis[x] = 1; q.pop(); for (auto y: e[x]) { dis[y] = max(dis[x], dis[x] + 1); if (--deg[y] == 0) q.push(y); } } int res = 0; for (int i = 1; i <= N; i++) { if (vis[i] == 0) res++; if (e[i].empty()) res += dis[i]; } cout << res; return 0; }

4|0E. Trade Road


可以参考官方题解的证明思路,得到以下引理

不存在市场两两不相同的A,B,C,D,使得商路AB,CD同时存在

因此,最终的结果一定是有两种

  1. 所有商路要么从x出发,要么到达x
  2. x为顶角的等腰三角形。

因此找到从每一个点出发的最远点,然后枚举x就好了,我这里找最远点采用了二分,而不是官解的双指针。

#include <bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; using ldb = long double; #define int i64 using vi = vector<int>; int K; int dis(int x, int y) { return min(((x - y) % K + K) % K, ((y - x) % K + K) % K); } int norm(int x) { return (x % K + K) % K; } i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int n; cin >> K >> n; vi a(n + 1); map<int, int> idx; set<int> vis; for (int i = 1; i <= n; i++) { cin >> a[i], a[i]--, idx[a[i]] = i; vis.insert(a[i] - K - K); vis.insert(a[i] - K); vis.insert(a[i]); vis.insert(a[i] + K); vis.insert(a[i] + K + K); } vector<vi> e(n + 1); vector<map<int, int>> road(n + 1); vi cnt(n + 1); for (int i = 1; i <= n; i++) { set<int> b; int x = a[i] + K / 2; b.insert(norm(*vis.lower_bound(x))); b.insert(norm(*prev(vis.upper_bound(x)))); x++; b.insert(norm(*vis.lower_bound(x))); b.insert(norm(*prev(vis.upper_bound(x)))); int maxD = 0; for (auto j: b) maxD = max(maxD, dis(a[i], j)); for (auto y: b) if (dis(a[i], y) == maxD) { int j = idx[y]; e[i].push_back(j); cnt[j]++; road[i][j] = 1; } } int res = 0; for (int x = 1, ans; x <= n; x++) { ans = cnt[x]; for (auto y: e[x]) if (road[y][x] == 0) ans++; res = max(res, ans); if (e[x].size() == 2) { int y = e[x][0], z = e[x][1]; if (road[y][z]) res = max(res, 3ll); } } cout << res; return 0; }

5|0F. Try a try, AC is OK


与只会变小,所以序列最大值就是答案

#include <bits/stdc++.h> using namespace std; using i64 = long long; using vi = vector<int>; void solve() { int n; cin >> n; vi a(n); for (auto &i: a) cin >> i; cout << ranges::max(a) << "\n"; } int main() { ios::sync_with_stdio(false), cin.tie(nullptr); int T; cin >> T; while (T--) solve(); return 0; }

6|0G. Disappearing Number


一种类似数位 dp 的方法,枚举每一位的方案即可

#include <bits/stdc++.h> using namespace std; using i32 = int; using i64 = long long; #define int i64 using vi = vector<int>; void solve() { int n, x; cin >> n >> x; int pre = 1, sum = 1; while (n) { int y = n % 10; if (y > x) y--; sum += y * pre; pre = pre * 9, n /= 10; } cout << sum << "\n"; } i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int T; cin >> T; while (T--) solve(); return 0; }

7|0L. Chess


考虑到在任何进制下,个位数一定是成立的,且满足条件的y个位一定是非0的。

类似 bash 博弈,如果x的个位为 0 则一定无法一步拿完,同时如果个位不为 0 ,则一定可以通过一次操作使得个位为 0。因此如果x的个位为0,则先手一定必败。所以枚举进制,找到最小k进制使得x各个位不为 0 即可。

#include <bits/stdc++.h> using namespace std; using i32 = int; using i64 = long long; using vi = vector<int>; using pii = pair<int, int>; void solve() { i64 n; cin >> n; for (int i = 2;; i++) if (n % i != 0) { cout << i << "\n"; return; } return; } i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int T; cin >> T; while (T--) solve(); return 0; }

8|0M. Window Decoration


一个正方形的面积为 2,每一个相邻的正方形会公用0.5的面积,不会出现同一块被三个及以上的正方形覆盖的情况,因此简单容斥就好了

#include <bits/stdc++.h> using namespace std; using i32 = int; using i64 = long long; #define int i64 using vi = vector<int>; using pii = pair<int, int>; i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int n; cin >> n; vector<pii> a(n); for (auto &[x, y]: a) cin >> x >> y; sort(a.begin(), a.end()); a.resize(unique(a.begin(), a.end()) - a.begin()); double res = a.size() * 2; for (int i = 1; i < a.size(); i++) { auto [x, y] = a[i]; for (int j = 0; j < i; j++) { auto [p, q] = a[j]; if (abs(x - p) + abs(y - q) == 1) res -= 0.5; } } cout << fixed << setprecision(10) << res; return 0; }

__EOF__

本文作者PHarr
本文链接https://www.cnblogs.com/PHarr/p/18358908.html
关于博主:前OIer,SMUer
版权声明CC BY-NC 4.0
声援博主:如果这篇文章对您有帮助,不妨给我点个赞
posted @   PHarr  阅读(96)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
历史上的今天:
2022-08-14 第五届新疆省ACM-ICPC程序设计竞赛
点击右上角即可分享
微信分享提示