前言:
大二,第二次打ccpc线下赛,和队友A5题,罚时太多、邀请赛铜牌和省赛铜牌。因为小失误很多,KL两题没开出来,没有发挥出队伍应有的实力。
题目链接: Dashboard - 2024 National Invitational of CCPC (Zhengzhou), 2024 CCPC Henan Provincial Collegiate Programming Contest - Codeforces
Problem F. 优秀字符串(签到)
我和队友分别从后往前、从前往后看题。看出来M是个二分,准备写M,看榜发现F过的很多。看F,发现是个签到,就先开F.
签到题,没啥说的,模拟一下
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int, int> pii; #define int long long const int N = 1e5 + 10, mod = 1e9 + 7; int ans; void solve() { string s; cin >> s; set<char> q; for (int i = 0; i < min((int)s.size(), 4LL); i++) { q.insert(s[i]); } if (s.size() == 5 && s[2] == s[4] && q.size() == 4) ans++; } signed main() { ios::sync_with_stdio(0); cin.tie(0); int t; cin >> t; while (t--) solve(); cout << ans << "\n"; return 0; }
Problem B. 扫雷 1(贪心)
看的时候以为是个dp,发现不对,直接贪心就能过。
可以统计一下,每个数出现的最后位置的下标。然后从小到大开始选择,同时修改now即可,表示now以及之前的钱都用来买这个位置的装置。now==n结束
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int, int> pii; #define int long long const int N = 1e5 + 10, mod = 1e9 + 7; void solve() { int n; cin >> n; map<int, int> mp; for (int i = 1; i <= n; i++) { int x; cin >> x; mp[x] = i; } int ans = 0; int now = 0; int money = 0; for (auto [w, idx] : mp) { money += (idx - now); if (money >= w) { ans += money / w; money %= w; } now = idx; if (now == n) break; } cout << ans << "\n"; } signed main() { ios::sync_with_stdio(0); cin.tie(0); int t; t = 1; while (t--) solve(); return 0; }
Problem M. 有效算法(二分)
一眼二分,因为k越大,每个ai能变化的范围就越大,有单调性,判断区间能不能重叠,所以直接上二分。
边界l是可以为0的,表示每个ai都不变,适用于ai相同的情况,但我们没有考虑到,猛吃了两发罚时。
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int, int> pii; #define int long long const int N = 1e5 + 10, mod = 1e9 + 7; void solve() { int n; cin >> n; vector<int> a(n + 1), b(n + 1); for (int i = 1; i <= n; i++) { cin >> a[i]; } for (int i = 1; i <= n; i++) { cin >> b[i]; } int l = 0, r = 1e9; auto check = [&](int mid) -> bool { int ll = -1e18, rr = 1e18; for (int i = 1; i <= n; i++) { ll = max(ll, a[i] - mid * b[i]); rr = min(rr, a[i] + mid * b[i]); } if (ll > rr) return 0; return 1; }; while (l < r) { int mid = l + r >> 1; if (check(mid)) { r = mid; } else l = mid + 1; } cout << l << '\n'; } signed main() { ios::sync_with_stdio(0); cin.tie(0); int t; cin >> t; while (t--) solve(); return 0; }
Problem J. 排列与合数(暴力)
没有找性质,看一眼数据范围,发现就5位数。可以预处理1e4~1e5之间的数,然后跑全排列,时间复杂度是O(N*5!)完全能过。
我忘记了使用next_permutation函数前需要先将字符串排序,因此再次猛吃两发罚时。
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int, int> pii; #define int long long const int N = 1e5 + 10, mod = 1e9 + 7; bool st[N]; void solve() { string s; cin >> s; sort(s.begin(), s.end()); do { int now = 0; for (auto c : s) { now = now * 10 + c - '0'; } if (now < 10000) continue; if (st[now]) { cout << now << "\n"; return; } } while (next_permutation(s.begin(), s.end())); cout << -1 << "\n"; } signed main() { ios::sync_with_stdio(0); cin.tie(0); int t; cin >> t; for (int i = 10000; i <= 100000; i++) { for (int j = 2; j * j <= i; j++) { if (i % j == 0 && i / j >= 2) { st[i] = 1; } } } while (t--) solve(); return 0; }
Problem H. 随机栈
这题是两个队友开的,我这时在看k题,没有参与此题,因此放上官方题解。
赛后补题:
Problem L. Toxel 与 PCPC II(DP)
赛时一开始考虑贪心,发现不对,后改为DP,但实现过程中因为敲错变量,导致一直跑的是
复杂度的dp,赛后才发现,警钟撅烂。
定义dp数组为:在第i个bug前,已经解决了j个bug所需要花费的最小值。
以此推得dp转移方程为:
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int, int> pii; #define int long long const int N = 2e5 + 10, mod = 1e9 + 7; int f[N]; void solve() { int n, m; cin >> n >> m; for (int i = 1; i <= m; i++) { f[i] = 1e18; } for (int i = 1; i <= m; i++) { int x; cin >> x; for (int j = i; j >= max(0ll, i - 500); j--) { f[i] = min(f[i], f[j] + (i - j) * (i - j) * (i - j) * (i - j) + x); } } cout << f[m] << '\n'; } signed main() { ios::sync_with_stdio(0); cin.tie(0); int t; t = 1; while (t--) solve(); return 0; }
Problem K. 树上问题
还在调……
总结:
第一次参加区域赛形式的比赛,激动与紧张互存,省内队伍比去年变少了,来了很多省外的强队,比赛前3个人压力很大,比赛过程中出现很多失误,队伍发挥失常,没能拿出应有的实力。
前几题都是思维题,算法很常见,做不到1眼出题,还是要加训。
写到最后已经急了,开始红温了。导致L题的DP卡了很久也没能调出来,很可惜。团队合作是很重要的一点,找队友思维的漏洞,三个人如果自己写自己的,那只能打铁。