2023 CCPC 秦皇岛

1|0A. Make SYSU Great Again I


因为k2n,所以可以顺序按照以阶梯形状摆放,这样可以保证每行每列两个,且gcd都是 1,剩下的数字随便放就好了。

#include <bits/stdc++.h> using namespace std; using i32 = int32_t; 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, k; cin >> n >> k; int t = 1; for (int i = 1; i <= n and t <= k; i++) { cout << i << " " << i << "\n", t++; if (i == n) cout << i << " " << 1 << "\n", t++; else cout << i << " " << i + 1 << "\n", t++; } for (int i = 1; i <= n and t <= k; i++) { for (int j = 1 + ( i == n); j < i and t <= k; j++) { cout << i << " " << j << "\n", t++; } for (int j = i + 2; j <= n and t <= k; j++) { cout << i << " " << j << "\n", t++; } } return 0; }

2|0D. Yet Another Coffee


考虑一种贪心的情况,把所有的打折卡按照结束时间排序,然后我们逐个打折卡考虑,我们把打折卡给最便宜的咖啡使用一定最优,因为打折卡是使得价格为负数。操作完后,贪心的选择最便宜的即可。

#include <bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; #define int i64 using vi = vector<int>; using pii = pair<int, int>; void solve() { int n, m; cin >> n >> m; vi a(n); for (auto &i: a) cin >> i; vector<pii> b(m); for (auto &[r, w]: b) cin >> r >> w; ranges::sort(b); multiset<int> pre; int t = 0; for (int x; auto [r, w]: b) { while (t < n and t < r) pre.insert(a[t++]); x = *pre.begin(), pre.erase(pre.begin()), pre.insert(x - w); } while (t < n) pre.insert(a[t++]); for (int i = 1, res = 0; i <= n; i++) { res += *pre.begin(), pre.erase(pre.begin()); cout << res << " "; } cout << "\n"; return; } i32 main() { ios::sync_with_stdio(false), cin.tie(nullptr); int T; cin >> T; while (T--) solve(); return 0; }

3|0F. Mystery of Prime


找规律发现对于两个奇偶相同的数x,y,存在一个数k可以使得x+k,y+k均为质数。然后相邻的两个数奇偶必须不同,除了一种特殊情况,就是两个1相邻。

因此我们可以设计状态f[i][0/1/2/3]表示前i个数,且第i个数的状态为0不改变、1修改为12修改为奇数、3修改为偶数。

然后转移就可以分为两类,一种相邻两个数,我们根据刚才说的奇偶不同和两个1的情况进行转移。还有一种是相邻三个数,两侧的数字就相同的情况。

#include<bits/stdc++.h> using namespace std; using vi = vector<int>; const int inf = INT_MAX / 2; bool is_prime(int x) { if (x < 2) return false; for (int i = 2; i * i <= x; i++) if (x % i == 0) return false; return true; } int main() { int n; cin >> n; vi a(n + 1); for (int i = 1; i <= n; i++) cin >> a[i]; if (n == 2) { if (is_prime(a[1] + a[2])) cout << 0; else cout << 1; return 0; } vector f(n + 1, vi(4, inf));// 0 不变, 1 变1, 2 变奇, 3 变偶 f[1][0] = 0; f[1][1] = (a[1] != 1); f[1][2] = f[1][3] = 1; for (int i = 2; i <= n; i++) { // 0 if (is_prime(a[i] + a[i - 1])) f[i][0] = min(f[i][0], f[i - 1][0]); if (is_prime(a[i] + 1)) f[i][0] = min(f[i][0], f[i - 1][1]); if (a[i] % 2 == 1) f[i][0] = min(f[i][0], f[i - 1][3]); else f[i][0] = min(f[i][0], f[i - 1][2]); // 1 if (is_prime(1 + a[i - 1])) f[i][1] = min(f[i][1], f[i - 1][0] + (a[i] != 1)); f[i][1] = min(f[i][1], f[i - 1][1] + (a[i] != 1)); f[i][1] = min(f[i][1], f[i - 1][3] + (a[i] != 1)); // 2 if (a[i - 1] % 2 == 0) f[i][2] = min(f[i][2], f[i - 1][0] + 1); f[i][2] = min(f[i][2], f[i - 1][3] + 1); // 3 if (a[i - 1] % 2 == 1) f[i][3] = min(f[i][3], f[i - 1][0] + 1); f[i][3] = min(f[i][3], f[i - 1][1] + 1); f[i][3] = min(f[i][3], f[i - 1][2] + 1); // 改中间 f[i][1] = min(f[i][1], f[i - 2][1] + 1 + (a[i] != 1)); // 1 x 1 f[i][1] = min(f[i][1], f[i - 2][2] + 1 + (a[i] != 1)); // 奇 x 1 f[i][2] = min(f[i][2], f[i - 2][2] + 2); // 奇 x 奇 f[i][2] = min(f[i][2], f[i - 2][1] + 2); // 1 x 奇 f[i][3] = min(f[i][3], f[i - 2][3] + 2); // 偶 x 偶 if (a[i] % 2 == 1) { // ai 是 奇 f[i][0] = min(f[i][0], f[i - 2][1] + 1); // 1 x ai f[i][0] = min(f[i][0], f[i - 2][2] + 1); // 奇 x ai if (a[i - 2] % 2 == 1) f[i][0] = min(f[i][0], f[i - 2][0] + 1); // ai-2 x ai } else { // ai 是 偶 f[i][0] = min(f[i][0], f[i - 2][3] + 1);// 偶 x ai if (a[i - 2] % 2 == 0) f[i][0] = min(f[i][0], f[i - 2][0] + 1); // ai-2 x ai } } cout << ranges::min(f[n]); return 0; }

4|0G. Path


手推一下发现,其实答案就是|aiai1|+|bibi1|

#include <bits/stdc++.h> using namespace std; using i32 = int32_t; 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, m; cin >> n >> m; vi a(n), b(m); for (auto &i: a) cin >> i; for (auto &i: b) cin >> i; int res = 0; for (int i = 1; i < n; i++) res += abs(a[i] - a[i - 1]); for (int i = 1; i < m; i++) res += abs(b[i] - b[i - 1]); cout << res; return 0; }

5|0J. Keyi LIkes Reading


其实只有13个物品,然后我们可以设计状态f[i][j]表示前i天选了j是否成立。其中j是二进制表示那些被选了。

因此我们可以用O(13×(213)2)的代价转移出来。

#include <bits/stdc++.h> using namespace std; using i32 = int32_t; 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); vi cnt(13); int n, w; cin >> n >> w; for (int i = 1, x; i <= n; i++) cin >> x, cnt[x - 1]++; ranges::sort(cnt, greater<>()); n = 0; while (n < 13 and cnt[n] != 0) n++; cnt.resize(n); vi can; int N = 1 << n; for (int i = 1, sum; i < N; i++) { sum = 0; for (int j = 0; j < n; j++) if ((i >> j) & 1) sum += cnt[j]; if (sum <= w) can.push_back(i); } vi f(N); f[0] = 1; for (int i = 1; i <= n; i++) { auto g = f; for (int t = 1; t < N; t++) { for (auto p: can) { if ((t | p) != t) continue; g[t] |= f[t ^ p]; } } f = move(g); if (f[N - 1]) { cout << i << "\n"; return 0; } } return 0; }

然后赛时因为写错了一点,导致越界进而导致 TLE。我按头写了一个优化,首先我们倒序枚举,这样可以优化空间,然后对于状态j,我强制要求当前学习的单词中包含了jmsg,这样的话可以把复杂度减小113msg是最高有效位。

#include <bits/stdc++.h> using namespace std; using i32 = int32_t; 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); vi cnt(13); int n, w; cin >> n >> w; for (int i = 1, x; i <= n; i++) cin >> x, cnt[x - 1]++; ranges::sort(cnt, greater<>()); n = 0; while (n <= 13 and cnt[n] != 0) n++; cnt.resize(n); auto msg = [&](int x) { for (int i = n - 1; i >= 0; i--) { if ((x >> i) & 1) return i; } }; vector<vi> can(n); int N = 1 << n; for (int i = 1, sum; i < N; i++) { sum = 0; for (int j = 0; j < n; j++) if ((i >> j) & 1) sum += cnt[j]; if (sum <= w) can[msg(i)].push_back(i); } vi f(N); f[0] = 1; for (int i = 1; i <= n; i++) { for (int t = N - 1; t >= 1; t--) { if (f[t]) continue; for (auto p: can[msg(t)]) { if ((t | p) != t) continue; if (f[t ^ p] == 0)continue; f[t] = 1; break; } } if (f[N - 1]) { cout << i << "\n"; return 0; } } return 0; }

__EOF__

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