2018-2019 ACM-ICPC, China Multi-Provincial Collegiate Programming Contest

1|0A. Maximum Element In A Stack


按照题目模拟就好,栈内的最大值可以维护单调栈解决。

#include <bits/stdc++.h> using namespace std; using i64 = long long; using ui32 = unsigned int; ui32 SA, SB, SC; ui32 rng61(){ SA ^= SA << 16; SA ^= SA >> 5; SA ^= SA << 1; ui32 t = SA; SA = SB; SB = SC; SC ^= t ^ SA; return SC; } void solve() { int n, p, q, m; cin >> n >> p >> q >> m >> SA >> SB >> SC; stack<ui32> s; i64 res = 0; for(ui32 i = 1; i <= n ; i ++) { if(rng61() % (p + q) < p) { ui32 tmp = (rng61() % m + 1); if(s.empty()) s.push(tmp); else s.push(max(s.top(), tmp)); } else if(not s.empty()) s.pop(); if(not s.empty()) res ^= (i64)i * (i64)s.top(); } cout << res << "\n"; } int main() { ios::sync_with_stdio(false), cin.tie(nullptr); int TC; cin >> TC; for(int i = 1; i <= TC; i ++) cout << "Case #" << i << ": ", solve(); return 0; }

2|0B. Rolling The Polygon


偏模板的题目,通过三个点算出夹角,然后根据半径算一下弧长就好了。

#include<bits/stdc++.h> using namespace std; using i32 = int32_t; #define int long long using vi = vector<int>; using pii = pair<int, int>; const int inf = 1e9; using db = long double; struct Point { db x, y; Point(db x = 0, db y = 0) : x(x), y(y) {}; }; using Vec = Point; const db pi = acosl(-1); Vec operator+(Vec u, Vec v) { return Vec(u.x + v.x, u.y + v.y); } Vec operator-(Vec u, Vec v) { return Vec(u.x - v.x, u.y - v.y); } db operator*(Vec u, Vec v) { return u.x * v.x + u.y * v.y; } db len(Vec v) { return sqrt(v.x * v.x + v.y * v.y); } db cos_t(Vec u, Vec v) { return u * v / len(u) / len(v); } using Points = vector<Point>; ostream &operator<<(ostream &os, Point x) { return os << "(" << x.x << "," << x.y << ")"; } void solve() { int n; cin >> n; Points ps(n); for (auto &[x, y]: ps) cin >> x >> y; Point po; cin >> po.x >> po.y; db res = 0; for (int i = 0, lst = n - 1, nxt = 1; i < n; i++, lst = (lst + 1) % n, nxt = (nxt + 1) % n) { Vec v1 = ps[nxt] - ps[i], v2 = ps[lst] - ps[i]; db theta = acosl(cos_t(v1, v2)); res += (pi - theta) * len(po - ps[i]); } cout << fixed << setprecision(3) << res << "\n"; return; } i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int T = 1; cin >> T; for (int i = 1; i <= T; i++) cout << "Case #" << i << ": ", solve(); }

3|0C. Caesar Cipher


#include <bits/stdc++.h> using namespace std; void solve() { int n, m; cin >> n >> m; string a, b, c; cin >> a >> b >> c; int d = (a.front() - b.front() + 26) % 26; for (auto i: c) cout << char((i - 'A' + d) % 26 + 'A'); cout << "\n"; return ; } signed main() { ios::sync_with_stdio(false), cin.tie(nullptr); int T = 1; cin >> T; for( int i = 1 ; i <= T ; i ++ ) cout << "Case #" << i << ": ", solve(); return 0; }

4|0D. Take Your Seat


打表找找规律就好了

#include <bits/stdc++.h> using namespace std; #define ll long long using vi = vector<int>; void solve() { int n, m; cin >> n >> m; long double x = 1, y = 0; for (int i = 1; i <= m; i++) x += 1, y += 2; cout << fixed << setprecision(6) << (n == 1 ? 1.0 : 0.5) << " " << x / y << "\n"; return; } signed main() { ios::sync_with_stdio(false); cin.tie(nullptr); int T; cin >> T; for (int i = 1; i <= T; i++) { cout << "Case #" << i << ": "; solve(); } return 0; }

5|0F. Moving On


离线做,询问按照w进行排序。然后每次加入一个点之后,把进行一次松弛操作。

#include<bits/stdc++.h> using namespace std; using i32 = int32_t; #define int long long using vi = vector<int>; using pii = pair<int, int>; const int inf = 1e9; void solve() { int n, q; cin >> n >> q; vector<pii> a; for (int i = 1, x; i <= n; i++) cin >> x, a.emplace_back(x, i); sort(a.begin(), a.end()); vector g(n + 1, vi(n + 1)); for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) cin >> g[i][j]; vector<array<int, 4>> op(q); for (int id = 0; auto &[w, u, v, idx]: op) cin >> u >> v >> w, idx = id++; sort(op.begin(), op.end()); vi res(q); for (int t = 0; const auto &[w, u, v, idx]: op) { while (t < n and a[t].first <= w) { int x = a[t].second; for (int i = 1; i <= n; i++) for (int j = 1; j < i; j++) g[i][j] = g[j][i] = min(g[i][j], g[i][x] + g[x][j]); t++; } res[idx] = g[u][v]; } for (auto &i: res) cout << i << "\n"; return; } i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int T = 1; cin >> T; for (int i = 1; i <= T; i++) cout << "Case #" << i << ":\n", solve(); return 0; }

6|0G. Factories


这本身是一个无根树,所以先找一个不是叶子的点做根。

dp[i][j]表示i的子树中选择k个叶子点的最小代价,u是根节点,v是子节点,则转移如下

dp[u][i]=dp[u][i1]+dp[v][j]+w(kj)j

其中w(kj)j表示从vu的边产生的贡献。

#include <bits/stdc++.h> using namespace std; #define ll long long const ll inf = 1e18; const int N = 1e5 + 6; int n,k; ll dp[N][110]; vector<pair<int,ll>> e[N]; void dfs(int u,int prv){ for (auto [v,w] : e[u]) if (v != prv){ dfs(v,u); for (int i = k;i >= 0;i--){ for (int j = i;j >= 0;j--){ dp[u][i] = min(dp[u][i],dp[u][i - j] + dp[v][j] + w * (k - j) * (j)); } } } } void solve(){ cin >> n >> k; for (int i = 1;i <= n;i++){ e[i].clear(); } for (int i = 1;i <= n - 1;i++){ int u,v,w;cin >> u >> v >> w; e[u].push_back({v,w}); e[v].push_back({u,w}); } int root = -1; if (k == 1){ cout << 0 << endl; return; } for (int i = 1;i <= n;i++){ if (e[i].size() != 1){ root = i; break; } } for (int i = 1;i <= n;i++){ for (int j = 0;j <= k;j++){ dp[i][j] = inf; } } for (int i = 1;i <= n;i++){ dp[i][0] = 0; } for (int i = 1;i <= n;i++){ if (e[i].size() == 1){ dp[i][1] = 0; } } if (root == -1){ int ans = 0; for (int i = 1;i <= n;i++){ for (auto [v,w] : e[i]){ ans += w; } } cout << ans / 2 << endl; }else{ dfs(root,-1); cout << dp[root][k] << endl; } } signed main() { ios::sync_with_stdio(false); cin.tie(nullptr); int T;cin >> T; for (int i = 1;i <= T;i++){ cout << "Case #" << i << ": "; solve(); } return 0; }

7|0H. Fight Against Monsters


贪心做,先计算出击败一个怪物需要的次数cnt,然后按照stkcnt从大到小逐个击杀。

#include <bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; #define int i64 using vi = vector<int>; void solve() { int n; cin >> n; vector<tuple<double, int, int>> a; int sum = 0; for (int i = 1, hp, atk; i <= n; i++) { cin >> hp >> atk, sum += atk; int l = 1, r = hp, cnt = -1; while (l <= r) { int mid = (l + r) / 2; if (mid * (mid + 1) / 2 >= hp) cnt = mid, r = mid - 1; else l = mid + 1; } a.emplace_back(double(atk) / (double) cnt, atk, cnt); } sort(a.begin(), a.end(), greater<>()); int res = 0; for (auto &[x, atk, cnt]: a) { res += cnt * sum; sum -= atk; } cout << res << "\n"; } i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int TC; cin >> TC; for (int i = 1; i <= TC; i++) cout << "Case #" << i << ": ", solve(); return 0; }

8|0K. Vertex Covers


我们可以把点分成两部分,然后可以先计算左边的部分,如果左边有一个点不在集合中,则左边所有与他相连的点都必须在集合内,否则不合法。

同理,在枚举右边的集合。对于一个合法的集合,当右边一个点不在集合中,则与这个点所有相连的左侧的点必须在左侧集合中,我们可以根据这个求出左边集合的必选点,这左边集合必须是必选点的超集。

我们可以用高维前缀和,处理出左边集合每个集合超集的和。

#include <bits/stdc++.h> using namespace std; using i32 = int32_t; #define int long long using vi = vector<int>; void solve(){ int n, m, p; cin >> n >> m >> p; vi val(n); for(auto &i : val) cin >> i; vector e(n ,vi(n)); for(int u, v; m; m --) { cin >> u >> v, u --, v --; e[u][v] = e[v][u] = 1; } int n1 = n / 2, n2 = n - n1; vi f(1<<n1); for(int i = 0; i < (1<<n1); i ++ ){ auto tmp = 1; for(int j = 0; j < n1 and tmp; j ++){ if(i & (1<<j)) tmp = tmp * val[j] % p; else { for(int k = 0; k < n1 and tmp; k ++) if(not (i & (1<<k)) and e[j][k] ) // k 也不在集合中,且 j,k 之间有边 tmp = 0; } } f[i] = tmp; } // SOS DP, 枚举超集 for(int j = 0; j < n1; j ++) for(int i = 0; i < (1<<n1); i ++) if(not(i &(1<<j))) f[i] = (f[i] + f[i ^ (1<<j)]) % p; int res = 0; for(int i = 0; i < (1<<n2); i ++){ int tmp = 1; for( int j = 0; j < n2 and tmp; j ++){ if(i & (1<<j)) tmp = tmp * val[n1 + j] % p; else { for(int k = 0; k < n2 and tmp; k ++) if(not (i & (1<<k)) and e[n1 + j][n1 + k]) tmp = 0; } } if(tmp == 0) continue; int need = 0; for(int j = 0; j < n2; j ++){ if(i & (1<<j)) continue; for(int k = 0; k < n1; k ++) if(e[n1 + j][k]) // j 没被选 且 j,k 之间存在边,则 k 必选 need |= (1<<k); } res = (res + tmp * f[need] % p) % p; } cout << res << "\n"; return; } i32 main(){ ios::sync_with_stdio(false), cin.tie(nullptr); int T; cin >> T; for(int i = 1; i <= T; i ++) cout << "Case #" << i << ": ", solve(); return 0; }

__EOF__

本文作者PHarr
本文链接https://www.cnblogs.com/PHarr/p/18163922.html
关于博主:前OIer,SMUer
版权声明CC BY-NC 4.0
声援博主:如果这篇文章对您有帮助,不妨给我点个赞
posted @   PHarr  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示